【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
原创粉丝点击