【BLE】CC2541之spi从模式的中断接收
来源:互联网 发布:c语言中char数据类型为 编辑:程序博客网 时间:2024/06/06 06:55
本篇博文最后修改时间:2017年01月06日,11:06。
一、简介
本文介绍CC2541的spi作为从模式、且中断接收时,要注意的事项,以及附上裸机代码和协议栈代码(非DMA)。
二、实验平台
主机: 3221
从机: CC2541
通讯方式: SPI
波特率: 1M
协议栈版本: 1.3.2
编译软件: IAR8.20.2
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
香瓜BLE之Android群:541462902
香瓜单片机之STM8/STM32群:164311667
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
四、实验前提
1、在进行本文步骤前,请先阅读以下博文:
暂无
2、在进行本文步骤前,请先实现以下博文:
暂无
五、注意事项
1、2541裸机:
3221需要在每个字节发送后延时10us,2541的SPI通信数据才能正常,否则丢数据。
2、2541上协议栈:
1)在SimpleBLEPeripheral的应用层初始化中注释掉:
HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT );
PS:这条语句会让空闲的CPU自动进入低频以此降低功耗,注释掉代表不自动切换频率。
2)在SimpleBLEPeripheral的应用层初始化中添加:
HCI_EXT_HaltDuringRfCmd(HCI_EXT_HALT_DURING_RF_DISABLE);
PS:这条语句会让RF期间停止MCU,默认是ENABLE的。
3)协议栈的临界区、广播、蓝牙连接,都会影响2541的SPI中断接收。
所以,UART或SPI应尽量使用DMA方式进行接收。
六、SPI代码例程
代码都是我自己写的,请忽略一些测试、协议相关的代码,自行修改。
1、SPI裸机代码
/************************************************************************************************** Filename: main.c Description: 裸机下的SPI从机代码 Date: 2015-06-17 Author: 甜甜的大香瓜 **************************************************************************************************/#include <ioCC2540.h>#include <string.h>//******************************************************************************// MACROS//****************************************************************************** //引脚 usart1 spi —— alt.2 #define SPI_CS P1_4 #define SPI_CLK P1_5#define SPI_MOSI P1_6 #define SPI_MISO P1_7//寄存器#define UxCSR U1CSR#define UxUCR U1UCR#define UxDBUF U1DBUF#define UxBAUD U1BAUD#define UxGCR U1GCR#define PxSEL P1SEL#define HAL_UART_PERCFG_BIT 0x02 // USART1 on P1, Alt-2; so set this bit.#define HAL_UART_PRIPO 0x40 // USART1 priority over UART0.#define HAL_UART_Px_SEL_S 0xF0 // Peripheral I/O Select for Slave: SO/SI/CLK/CSn.#define HAL_UART_Px_SEL_M 0xE0 // Peripheral I/O Select for Master: MI/MO/CLK.// UxCSR - USART Control and Status Register.#define CSR_MODE 0x80#define CSR_RE 0x40#define CSR_SLAVE 0x20#define CSR_FE 0x10#define CSR_ERR 0x08#define CSR_RX_BYTE 0x04#define CSR_TX_BYTE 0x02#define CSR_ACTIVE 0x01// UxUCR - USART UART Control Register.#define UCR_FLUSH 0x80#define UCR_FLOW 0x40#define UCR_D9 0x20#define UCR_BIT9 0x10#define UCR_PARITY 0x08#define UCR_SPB 0x04#define UCR_STOP 0x02#define UCR_START 0x01//其他#define uint8 unsigned char #define uint16 unsigned short//******************************************************************************//name: test//introduce: 测试//parameter: none//return: none//******************************************************************************uint8 tx_buf[256] = {0};uint8 rx_buf[256] = {0};uint8 tx_index = 0;uint8 rx_index = 0;void test_init(void){ uint16 i = 0; for(i = 0; i < 256; i++) { tx_buf[i] = i; }}void test(void){ UTX1IF = 0; if(UxCSR & CSR_RX_BYTE){ //receive a byte rx_buf[rx_index++] = UxDBUF; UxDBUF = tx_buf[tx_index++]; }}//****************************************************************************//名 称: SPI_Init()//功 能: 无//入口参数: 无//出口参数: 无//****************************************************************************void SPI_Init(void){ volatile uint8 receive = 0; PERCFG |= HAL_UART_PERCFG_BIT; // Set UART1 I/O to Alt. 2 location on P1. PxSEL |= HAL_UART_Px_SEL_S; // SPI-Slave peripheral select. UxCSR = CSR_SLAVE; // Mode is SPI-Slave Mode. UxUCR = UCR_FLUSH; // Flush it. UxGCR |= (1 << 5); // Set bit order to MSB. //UxGCR &= ~(1 << 6); // CPHA UxGCR |= (1 << 6); // CPHA UxGCR |= (1 << 7); // CPOL TCON &= ~(1 << 7); //清空usart1接收中断标志位 IEN0 |= (1 << 3); //使能usart1接收中断 IP0 &= ~(1 << 3); //设置spi的中断组为等级2 IP1 |= (1 << 3); UxCSR |= CSR_RE; //使能 //SPI_Response_Byte(RESPONSE_RECEIVING); //将0xF4写入发送寄存器中待发送 UxDBUF = tx_buf[tx_index++]; receive = UxDBUF; //读寄存器,防止里面有残留数据 //测试!!!!!!! test_init();}//****************************************************************************//程序入口函数//****************************************************************************void main(void){ CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振稳定为32M CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ EA = 1; SPI_Init(); //调用串口初始化函数 while(1); }//******************************************************************************//name: SPI_Rx_ISR//introduce: SPI接收中断函数//parameter: none//return: none//******************************************************************************#pragma vector = URX1_VECTOR __interrupt void SPI_Rx_ISR(void) { test(); }
2、SPI协议栈代码
1)spi.c
/************************************************************************************************** Filename: spi.c Description: spi slave driver Date: 2015-06-17 Author: 甜甜的大香瓜**************************************************************************************************///******************************************************************************// INCLUDES//******************************************************************************#include <ioCC2541.h> #include "spi.h" #include "OSAL.h"#include "hal_mcu.h"#include <string.h>//******************************************************************************// MACROS//****************************************************************************** //引脚 usart1 spi —— alt.2 #define SPI_CS P1_4 #define SPI_CLK P1_5#define SPI_MOSI P1_6 #define SPI_MISO P1_7//寄存器#define UxCSR U1CSR#define UxUCR U1UCR#define UxDBUF U1DBUF#define UxBAUD U1BAUD#define UxGCR U1GCR#define PxSEL P1SEL#define HAL_UART_PERCFG_BIT 0x02 // USART1 on P1, Alt-2; so set this bit.#define HAL_UART_PRIPO 0x40 // USART1 priority over UART0.#define HAL_UART_Px_SEL_S 0xF0 // Peripheral I/O Select for Slave: SO/SI/CLK/CSn.#define HAL_UART_Px_SEL_M 0xE0 // Peripheral I/O Select for Master: MI/MO/CLK.// UxCSR - USART Control and Status Register.#define CSR_MODE 0x80#define CSR_RE 0x40#define CSR_SLAVE 0x20#define CSR_FE 0x10#define CSR_ERR 0x08#define CSR_RX_BYTE 0x04#define CSR_TX_BYTE 0x02#define CSR_ACTIVE 0x01// UxUCR - USART UART Control Register.#define UCR_FLUSH 0x80#define UCR_FLOW 0x40#define UCR_D9 0x20#define UCR_BIT9 0x10#define UCR_PARITY 0x08#define UCR_SPB 0x04#define UCR_STOP 0x02#define UCR_START 0x01//其他#define uint8 unsigned char #define uint16 unsigned short//协议相关#define SPI_MAX_PACKET_LEN 39#define SPI_MAX_DATA_LEN 35#define SPI_SOF 0x7E // Start-of-frame delimiter for SPI transport.#define SPI_EOF 0x7F // End-of-frame delimiter for SPI transport.#define Head_CTRL 1#define Head_COMMAND 0#define Head(x) ((p_spi_protocol_data->Head >> x) & 0x01)#define COMMAND_RF 1#define COMMAND_BLE 0#define SPI_LEN_INCR(LEN) st ( \ if (++(LEN) >= (SPI_MAX_DATA_LEN - 1)) \ { \ (LEN) = 0; \ } \)#define DATA_RESET(); {spiRxSte = spiRxSteSOF; spiRxIndex = 0;}//******************************************************************************// GLOBAL VARIABLES//******************************************************************************//typedef enum{RESPONSE_RECEIVING = 0xF4, //正在接收RESPONSE_RECEIVED = 0xF6, //接收完毕RESPONSE_RESEND = 0xF7 //请求重发}SPI_RESPONSE_BYTE;//typedef enum{SPI_MALLOC_DATA_RIGHT, SPI_MALLOC_DATA_ERROR, }SPI_MALLOC_DATA_STATUS;//协议包typedef enum{ spiRxSteSOF, spiRxSteLen, spiRxSteData } spiRxSte_t;//SPI接收状态typedef enum{ SPI_RxStatus_Receiving, SPI_RxStatus_Received, SPI_RxStatus_Right, SPI_RxStatus_Error } SPI_RXSTATUS;//协议中的核心数据typedef struct{ uint8 Length; uint8 Head; uint8 Sequence; uint8 Binary[32]; }SPI_PROTOCOL_DATA;SPI_PROTOCOL_DATA *p_spi_protocol_data; //接收数据要的全局变量spiRxSte_t spiRxSte = spiRxSteSOF; uint16 spiRxFcs = 0; //校验和uint8 spiRxIndex = 0; //指向接收核心数据缓冲区的第几位uint8 spi_rx[SPI_MAX_PACKET_LEN] = {0}; //接收缓冲区SPI_RXSTATUS spi_rx_status = SPI_RxStatus_Receiving;static volatile uint8 check_time = 0; //用于计数主机发送F4的次数,如果过多就超时//******************************************************************************// LOCAL FUNCTIONS//******************************************************************************static void SPI_Response_Byte(SPI_RESPONSE_BYTE tx);static SPI_MALLOC_DATA_STATUS SPI_Malloc_DATA(void);static uint8 SPI_Packet_Receive(void);static SPI_RXSTATUS SPI_Rx_Resolution(void);static SPI_RXSTATUS SPI_Status_Judge(uint8 status);static void SPI_Status_Deal(SPI_RXSTATUS status);//******************************************************************************//name: test//introduce: 测试//parameter: none//return: none//******************************************************************************/*volatile uint8 tx_buf[256] = {0};volatile uint8 rx_buf[256] = {0};volatile uint8 tx_index = 0;volatile uint8 rx_index = 0;*/uint8 tx_buf[256] = {0};uint8 rx_buf[256] = {0};uint8 tx_index = 0;uint8 rx_index = 0;void test_init(void){ uint16 i = 0; for(i = 0; i < 256; i++) { tx_buf[i] = i; }}void test(void){ volatile uint8 aa = 0; rx_buf[rx_index] = UxDBUF; UxDBUF = tx_buf[tx_index]; if(rx_buf[rx_index] == tx_buf[rx_index]){ rx_index++; tx_index++; } else{ aa =0x38; }}//******************************************************************************//name: SPI_Init//introduce: SPI初始化//parameter: none//return: none//******************************************************************************void SPI_Init(void){ volatile uint8 receive = 0; PERCFG |= HAL_UART_PERCFG_BIT; // Set UART1 I/O to Alt. 2 location on P1. PxSEL |= HAL_UART_Px_SEL_S; // SPI-Slave peripheral select. UxCSR = CSR_SLAVE; // Mode is SPI-Slave Mode. UxUCR = UCR_FLUSH; // Flush it. UxGCR |= (1 << 5); // Set bit order to MSB. //UxGCR &= ~(1 << 6); // CPHA UxGCR |= (1 << 6); // CPHA UxGCR |= (1 << 7); // CPOL TCON &= ~(1 << 7); //清空usart1接收中断标志位 IEN0 |= (1 << 3); //使能usart1接收中断 IP0 |= (1 << 3); //设置spi的中断组为等级3 //IP0 &= ~(1 << 3); //设置spi的中断组为等级2 IP1 |= (1 << 3); UxCSR |= CSR_RE; //使能 receive = UxDBUF; //读寄存器,防止里面有残留数据 //UxDBUF = tx_buf[tx_index++]; SPI_Response_Byte(RESPONSE_RECEIVING); //将0xF4写入发送寄存器中待发送 SPI_Malloc_DATA(); //分配内存 //测试!!!!!!! //test_init();} //******************************************************************************//name: SPI_Response_Byte//introduce: SPI从机应答函数//parameter: none//return: none//******************************************************************************static void SPI_Response_Byte(SPI_RESPONSE_BYTE tx) { UxDBUF = tx; //写到寄存器里}//******************************************************************************//name: SPI_Malloc_DATA//introduce: 给通信协议中的核心数据开辟一个缓冲区//parameter: none//return: none//******************************************************************************static SPI_MALLOC_DATA_STATUS SPI_Malloc_DATA(void) { //分配内存 p_spi_protocol_data = osal_mem_alloc(sizeof(SPI_PROTOCOL_DATA)); //申请缓冲区buffer //判断是否分配成功 if(p_spi_protocol_data){ //内存分配成功,缓冲区置0 osal_memset(p_spi_protocol_data, 0, sizeof(SPI_PROTOCOL_DATA)); return SPI_MALLOC_DATA_RIGHT; }else{ //内存分配失败,返回错误信息 return SPI_MALLOC_DATA_ERROR; }}//******************************************************************************//name: SPI_Poll//introduce: 扫描SPI//parameter: none//return: none//******************************************************************************void SPI_Poll(void) { switch(spi_rx_status) { case SPI_RxStatus_Received: spi_rx_status = SPI_Rx_Resolution(); break; default: //spi_rx_status = SPI_RxStatus_Receiving; break; }}//******************************************************************************//name: SPI_Rx_Resolution//introduce: 解析接收到的SPI数据//parameter: none//return: none//******************************************************************************static SPI_RXSTATUS SPI_Rx_Resolution(void) { uint8 length = spi_rx[0]; uint8 xox_h = spi_rx[length + 1]; uint8 xox_l = spi_rx[length + 2]; uint16 xox = 0; uint8 eof = spi_rx[length + 3]; //清除缓冲区 osal_memset(p_spi_protocol_data, 0, sizeof(SPI_PROTOCOL_DATA)); //拷贝接收缓冲区 osal_memcpy(p_spi_protocol_data, spi_rx, (length + 3)); //计算校验和 for(uint8 i = 0; i < (length + 1); i++){ //length if(i == 0){ xox = p_spi_protocol_data->Length; } //head else if(i == 1){ xox ^= p_spi_protocol_data->Head; } //sequence else if(i == 2){ xox ^= p_spi_protocol_data->Sequence; } //binary else{ xox ^= p_spi_protocol_data->Binary[i - 3]; } } //比较校验和 if((((uint8)(xox >> 8) & 0xff) != xox_h) || ((uint8)(xox & 0xff) != xox_l)){ //校验和出错 return SPI_RxStatus_Error; } //比较EOF if(eof == SPI_EOF){ //处理数据 if(Head(7) == Head_CTRL){ //CTRL switch((p_spi_protocol_data->Head) & 0x7F) //内部指令 { case 0x00:break; case 0x01:break; case 0x02:break; case 0x03:break; case 0x04:break; default:break; } } else{ //COMMAND switch((p_spi_protocol_data->Head) & (1 << 5)) { case COMMAND_BLE: break; case COMMAND_RF: break; default: break; } } return SPI_RxStatus_Right; } else{ return SPI_RxStatus_Error; } }//******************************************************************************//name: SPI_Packet_Receive//introduce: SPI数据包接收//parameter: none//return: 0:接收正常,1数据全部接收完毕,2数据出错,3扫描超时//******************************************************************************static uint8 SPI_Packet_Receive(void) { uint8 ch = UxDBUF; //接收数据 switch (spiRxSte) { //包头 case spiRxSteSOF: //包头 DATA_RESET(); if (ch == SPI_SOF){ spiRxSte = spiRxSteLen; //包头正常,指向长度段 check_time = 0; } else if (ch == 0xF5){ //超时处理 if(check_time++ > 200){ check_time = 0; return 3; } } else{ return 2; //包头接收出错 } break; //数据长度 case spiRxSteLen: //数据长度 if((ch >= 3) && (ch <= 34)){ spi_rx[spiRxIndex++] = ch; //保存数据长度 spiRxSte = spiRxSteData; //指向数据接收 } else{ DATA_RESET(); return 2; //包头接收出错 } break; //其他数据 case spiRxSteData: spi_rx[spiRxIndex] = ch; //保存数据 if(spiRxIndex++ == (spi_rx[0] + 3)){ //判断数据是否接收完 DATA_RESET(); return 1; //接收完毕 } break; default: DATA_RESET(); return 2; //数据出错 break; } return 0; //正常 }//******************************************************************************//name: SPI_Status_Judge//introduce: 状态判断//parameter: status:当前状态//return: 0:接收正常,1数据全部接收完毕,2数据出错//******************************************************************************static SPI_RXSTATUS SPI_Status_Judge(uint8 status){ switch(status) { //正在接收 case 0: return SPI_RxStatus_Receiving; //接收完毕 case 1: return SPI_RxStatus_Received; //接收出错 case 2: return SPI_RxStatus_Error; //扫描超时出错 case 3: return SPI_RxStatus_Error; default: return SPI_RxStatus_Error; }}//******************************************************************************//name: SPI_Status_Deal//introduce: 状态处理//parameter: none//return: none//******************************************************************************static void SPI_Status_Deal(SPI_RXSTATUS status){ switch(status) { //正在接收 case SPI_RxStatus_Receiving: SPI_Response_Byte(RESPONSE_RECEIVING); break; //接收完毕 case SPI_RxStatus_Received: SPI_Response_Byte(RESPONSE_RECEIVING); break; //接收出错 case SPI_RxStatus_Error: spi_rx_status = SPI_RxStatus_Receiving; //下次状态改回接收 SPI_Response_Byte(RESPONSE_RESEND); break; default:break; }}//******************************************************************************//name: SPI_Rx_ISR//introduce: SPI接收中断函数//parameter: none//return: none//******************************************************************************#pragma vector = URX1_VECTOR __interrupt void SPI_Rx_ISR(void) { uint8 status = 0; HAL_ENTER_ISR(); if(UxCSR & CSR_RX_BYTE){ //receive a byte //test(); switch(spi_rx_status) { case SPI_RxStatus_Receiving: status = SPI_Packet_Receive(); //接收数据 spi_rx_status = SPI_Status_Judge(status); //判断状态 SPI_Status_Deal(spi_rx_status); //处理数据 break; case SPI_RxStatus_Received: SPI_Response_Byte(RESPONSE_RECEIVING); //在接收完毕的状态,一直回0xF4。等待轮询改变状态 break; case SPI_RxStatus_Right: spi_rx_status = SPI_RxStatus_Receiving; //下次状态改回接收 SPI_Response_Byte(RESPONSE_RECEIVED); break; case SPI_RxStatus_Error: spi_rx_status = SPI_RxStatus_Receiving; //下次状态改回接收 SPI_Response_Byte(RESPONSE_RESEND); break; default: break; } } HAL_EXIT_ISR();}
2)spi.h
#ifndef _SPI_H_#define _SPI_H_void SPI_Init(void);void SPI_Poll(void);#endif
3)修改Hal_ProcessPoll
void Hal_ProcessPoll (){ SPI_Poll(); /* UART Poll */#if (defined HAL_UART) && (HAL_UART == TRUE) HalUARTPoll();#endif /* HID poll */#if (defined HAL_HID) && (HAL_HID == TRUE) usbHidProcessEvents();#endif#if defined( POWER_SAVING ) /* Allow sleep before the next OSAL event loop */ ALLOW_SLEEP_MODE();#endif}在主轮询中加入SPI的poll轮询函数。
4)修改SimpleBLEPeripheral_Init
void SimpleBLEPeripheral_Init( uint8 task_id ){ simpleBLEPeripheral_TaskID = task_id; HCI_EXT_HaltDuringRfCmd(HCI_EXT_HALT_DURING_RF_DISABLE);//在RF期间不关闭mcu SPI_Init();//spi初始化 …… //HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT );//注释掉 ……}
0 0
- 【BLE】CC2541之spi从模式的中断接收
- 蓝牙BLE基础:CC2541通信系列之模拟SPI协议
- 【BLE】CC2541之配对密码的重置
- 【BLE】CC2541之notify
- 【BLE】CC2541之按键
- 【BLE】CC2541之RSSI
- 【BLE】CC2541之OLED
- 【BLE】CC2541之indicate
- 【BLE】CC2541之timer3
- 【BLE】CC2541之看门狗
- 【BLE】CC2541之SNV
- 【BLE】CC2541之OAD
- 【BLE】CC2541之PWM
- 【BLE】CC2541之OAD
- 【BLE】CC2541之BTool
- 【BLE】CC2541之timer1
- 【BLE】CC2541之SBL
- 【BLE】CC2541之RSSI
- Android LayoutInflater原理分析
- MySQL详解(22)------------表结构优化
- oracle中if/else功能的实现的3种写法
- Linux 文件描述符设置为非阻塞的方法
- 抬头显示器影响行车安全?
- 【BLE】CC2541之spi从模式的中断接收
- ios学习8_KVC和字典转模型
- 系统繁忙 请稍后再试(ALI64)”
- MySQL学习笔记(23)-----------索引优化
- 服务器负载均衡——总结归
- Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(四)
- poj 3708
- TCP协议--TIME_WAIT状态
- Android学习笔记之AndroidManifest.xml文件解析