5169:NXP JN5169 使用硬件 SPI 从机收发数据

NXP JN5169使用硬件SPI从机收发数据

  • 一、SPI 从机介绍
  • 二、JN5169 从机代码
    • 1、中断模式
    • 2、轮询模式
  • 三、STC15W408AS 主机代码



一、SPI 从机介绍

        SPI 总线从接口允许 JN5169 与外围设备之间进行高速同步数据传输。 JN5169 作为 SPI 总线上的从设备运行,连接到 SPI 总线的外部设备作为主机。 引脚与 SPI 总线主接口不同,如下表所示:


        SPI 总线采用简单的移位寄存器数据传输方案,SPISSEL 用作低电平有效选择控制。 数据以先进先出的方式移出和移入有源设备,从而允许 SPI 总线设备同时发送和接收数据。 主机输出从机输入或主机输入从机输出数据传输是相对于外部主机产生的时钟信号 SPISCLK 的。

SPI总线从机包括以下功能:

  • 全双工同步数据传输
  • 从机到外部时钟高达 8 MHz
  • 支持8位传输(可先配置 MSB 或 LSB),每次传输之间 SPISSEL 均置为无效
  • 内部 FIFO,最大 255 个字节,用于发送和接收
  • 标准SPI总线模式 0; 数据在时钟正沿采样
  • 可屏蔽中断,用于接收 FIFO 不为空,发送 FIFO 为空,接收 FIFO 填充水平高于阈值,发送 FIFO 低于阈值,发送 FIFO 溢出,接收 FIFO 下溢,发送 FIFO 下溢,接收超时
  • 可编程的接收超时时间段允许生成一个中断,以提示如果在超时时间段内没有其他数据到达,则读取接收 FIFO

二、JN5169 从机代码

1、中断模式

#define MSBFALSE//spi从最高位开始传输#define LSBTRUE//spi从最低位开始传输uint8 TxBuff[10];//发送缓冲区uint8 RxBuff[10];//接收缓冲区void vCbSpiSlaveInt(uint32 u32Device, uint32 u32ItemBitmap){uint8 recv; if(E_AHI_DEVICE_SPIS == u32Device){//SPI从机中断 if((u32ItemBitmap & (1 << 0)) == E_AHI_SPIS_INT_RX_FIRST_MASK){ vPrintf("数据已在接收FIFO中接收,以前是空的\n"); } if((u32ItemBitmap & (1 << 1)) == E_AHI_SPIS_INT_TX_LAST_MASK){ vPrintf("发送FIFO中的最后一个剩余字节已发送,缓冲区为空\n"); } if((u32ItemBitmap & (1 << 2)) == E_AHI_SPIS_INT_RX_CLIMB_MASK){ //这个中断提示应用从接收缓冲区中读取数据 //等待一个读阈值中断或读超时中断,当出现其中一个中断时,将调用用户定义的回调函数来处理中断 //函数 u8AHI_SpiSlaveRxReadByte()在这个回调函数中被调用。 vPrintf("接收FIFO的填充级别已超过配置的阈值级别\n"); recv = u8AHI_SpiSlaveRxReadByte(); vPrintf("recv1 = %x\n", recv); recv = u8AHI_SpiSlaveRxReadByte(); vPrintf("recv2 = %x\n", recv); } if((u32ItemBitmap & (1 << 3)) == E_AHI_SPIS_INT_TX_FALL_MASK){ //等待一个写阈值中断来提示写入发送 FIFO //当出现这个中断时,将调用用户定义的回调函数来处理中断,vAHI_SpiSlaveTxWriteByte()在这个回调函数中被调用。 //这个中断提示应用写数据到发送缓冲区 //写入的字节数不应超出缓冲区大小减去缓冲区写阈值的结果。 vPrintf("发送FIFO的填充水平已降至配置的阈值水平以下\n"); vAHI_SpiSlaveTxWriteByte(0x99); } if((u32ItemBitmap & (1 << 4)) == E_AHI_SPIS_INT_RX_OVER_MASK){ vPrintf("数据已接收但接收FIFO已满或繁忙(因此数据被丢弃)\n"); } if((u32ItemBitmap & (1 << 5)) == E_AHI_SPIS_INT_TX_OVER_MASK){ vPrintf("发送FIFO已写入但已满\n"); } if((u32ItemBitmap & (1 << 6)) == E_AHI_SPIS_INT_RX_UNDER_MASK){ vPrintf("接收FIFO已读取但为空\n"); } if((u32ItemBitmap & (1 << 7)) == E_AHI_SPIS_INT_TX_UNDER_MASK){ vPrintf("尝试发送但发送FIFO为空或未准备好(因此通过SPI总线发送了0x00)\n"); } if((u32ItemBitmap & (1 << 8)) == E_AHI_SPIS_INT_RX_TIMEOUT_MASK){ //等待一个读阈值中断或读超时中断,当出现其中一个中断时,将调用用户定义的回调函数来处理中断 //函数 u8AHI_SpiSlaveRxReadByte()在这个回调函数中被调用。 vPrintf("发生接收超时(在此期间未接收到其他数据)\n"); recv = u8AHI_SpiSlaveRxReadByte(); vPrintf("recv3 = %x\n", recv); } }}PUBLIC void vSPI_Slave_Init(){bAHI_SpiSlaveEnable(FALSE,//SPISMISO : DIO13, SPISMOSI : DIO12MSB,//高位开始传输TxBuff,//发送缓冲区sizeof(TxBuff),//发送缓冲区大小1,//发送缓冲区的填充阈值,以字节为单位(0到255),这个阈值提示当发送缓冲区数据大小这个阈值时,从机应当向主机写数据RxBuff,//接收缓冲区sizeof(RxBuff),//接收缓冲区大小1,//接收缓冲区的填充阈值,以字节为单位(0到255),这个阈值提示当接收缓冲区数据大小这个阈值时,应当向接收缓冲区读取数据100,//接收超时时间,以微秒为单位(0到4095)0x1FF//中断使能位,这里开启9个中断);vAHI_SpiSlaveRegisterCallback(vCbSpiSlaveInt);//注册中断回调函数//向发送缓冲区写入原始数据。//写入的字节数必须不能超过缓冲区的大小。//默认情况下,如果发送 FIFO 为空且传输由远程 SPI 主机启动,则 SPI 从机将发送数据字节 0x00。//由于设置发送缓冲区的填充阈值为1,所以每到主机向从机读取一次数据,从机向主机发送一个发送缓冲区的数据,直至发送缓冲区为空(先进先出)vAHI_SpiSlaveTxWriteByte(0x56);vAHI_SpiSlaveTxWriteByte(0x57);vAHI_SpiSlaveTxWriteByte(0x58);vAHI_SpiSlaveTxWriteByte(0x59);vAHI_SpiSlaveTxWriteByte(0x60);}PUBLIC void AppColdStart(void){vAHI_WatchdogStop();(void) u32AHI_Init();vSPI_Slave_Init();vUartInit();vAHI_DelayXms(500);vPrintf("System init!\n");while (1) {}}PUBLIC void AppWarmStart(void){AppColdStart();}

效果图

2、轮询模式

#define MSBFALSE//spi从最高位开始传输#define LSBTRUE//spi从最低位开始传输uint8 TxBuff[10];uint8 RxBuff[10];PUBLIC void vSPI_Slave_Init(){bAHI_SpiSlaveEnable(FALSE,//SPISMISO : DIO13, SPISMOSI : DIO12MSB,//高位开始传输TxBuff,//发送缓冲区sizeof(TxBuff),//发送缓冲区大小1,//发送缓冲区的填充阈值,以字节为单位(0到255),这个阈值提示当发送缓冲区数据大小这个阈值时,从机应当向主机写数据RxBuff,//接收缓冲区sizeof(RxBuff),//接收缓冲区大小1,//接收缓冲区的填充阈值,以字节为单位(0到255),这个阈值提示当接收缓冲区数据大小这个阈值时,应当向接收缓冲区读取数据100,//接收超时时间,以微秒为单位(0到4095)0x00//中断使能位,这里关闭全部中断);//向发送缓冲区写入原始数据。//写入的字节数必须不能超过缓冲区的大小。//默认情况下,如果发送 FIFO 为空且传输由远程 SPI 主机启动,则 SPI 从机将发送数据字节 0x00。//由于设置发送缓冲区的填充阈值为1,所以每到主机向从机读取一次数据,从机向主机发送一个发送缓冲区的数据,直至发送缓冲区为空(先进先出)vAHI_SpiSlaveTxWriteByte(0x56);vAHI_SpiSlaveTxWriteByte(0x57);vAHI_SpiSlaveTxWriteByte(0x58);vAHI_SpiSlaveTxWriteByte(0x59);vAHI_SpiSlaveTxWriteByte(0x60);}PUBLIC void AppColdStart(void){uint8 sta, len, recv;vAHI_WatchdogStop();(void) u32AHI_Init();vSPI_Slave_Init();vUartInit();vAHI_DelayXms(500);vPrintf("System init!\n");//实际运行时把串口打印注释掉while (1) {sta = u8AHI_SpiSlaveStatus();if((sta & 0x01) == E_AHI_SPIS_STAT_RX_AVAIL_MASK){//接收缓冲区不为空len = u8AHI_SpiSlaveRxFillLevel();//vPrintf("接收缓冲区填充级别:%d\n", len);if((sta & 0x04) == E_AHI_SPIS_STAT_RX_ABOVE_MASK){//接收缓冲区填充级别高于阈值//vPrintf("接收FIFO的填充级别已超过配置的阈值级别\n");recv = u8AHI_SpiSlaveRxReadByte();vPrintf("recv1 = %x\n", recv);}else{//vPrintf("接收FIFO的填充水平已降至配置的阈值水平以下\n");}}else{//vPrintf("接收缓冲区为空\n");}if((sta & 0x02) == E_AHI_SPIS_STAT_TX_PENDING_MASK){//发送缓冲区不为空len = u8AHI_SpiSlaveTxFillLevel();//vPrintf("发送缓冲区填充级别:%d\n", len);if((sta & 0x08) == E_AHI_SPIS_STAT_TX_ABOVE_MASK){//发送缓冲区填充级别高于阈值//vPrintf("发送缓冲区填充级别高于阈值\n");}else{//vPrintf("发送FIFO的填充水平已降至配置的阈值水平以下\n");vAHI_SpiSlaveTxWriteByte(0x99);}}else{//vPrintf("发送缓冲区为空\n");vAHI_SpiSlaveTxWriteByte(0x99);}}}PUBLIC void AppWarmStart(void){AppColdStart();}

效果图


三、STC15W408AS 主机代码

#define SPI_S00x04#define SPI_S10x08#define SPIF0x80//SPSTAT.7#define WCOL0x40//SPSTAT.6#define SSIG0x80//SPCTL.7#define SPEN0x40//SPCTL.6#define DORD0x20//SPCTL.5#define MSTR0x10//SPCTL.4#define CPOL0x08//SPCTL.3#define CPHA0x04//SPCTL.2#define SPDHH0x00//CPU_CLK/4#define SPDH0x01//CPU_CLK/16#define SPDL0x02//CPU_CLK/64#define SPDLL0x03//CPU_CLK/128sbit SS = P1 ^ 2;//SPI_1的SS脚void InitSPI_1(void){ACC = P_SW1; //切换到第一组SPIACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=0 SPI_S1=0P_SW1 = ACC; //(P1.2/SS, P1.3/MOSI, P1.4/MISO, P1.5/SCLK)//ACC = P_SW1; //可用于测试U7,U7使用的是第二组SPI控制Flash//ACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=1 SPI_S1=0//ACC |= SPI_S0; //(P2.4/SS_2, P2.3/MOSI_2, P2.2/MISO_2, P2.1/SCLK_2)//P_SW1 = ACC;//ACC = P_SW1; //切换到第三组SPI//ACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=0 SPI_S1=1//ACC |= SPI_S1; //(P5.4/SS_3, P4.0/MOSI_3, P4.1/MISO_3, P4.3/SCLK_3)//P_SW1 = ACC;SPDAT = 0; //初始化SPI数据SPSTAT = SPIF | WCOL; //清除SPI状态位SPCTL = SPEN | MSTR | SSIG | SPDHH; //主机模式}uchar SPISwap(uchar dat){SPDAT = dat; //触发SPI发送数据while((SPSTAT & SPIF) != SPIF); //等待发送完成SPSTAT = SPIF | WCOL; //清除SPI状态位return SPDAT; //返回SPI数据}uchar spi_send_byte(uchar dat){uchar recv = 0;SS = 0;recv = SPISwap(dat);SS = 1;return recv;}void main(void){InitSPI_1();Init_Uart();EA = 1;Delay500ms();Delay500ms();printf("System init\r\n");while(1) {printf("recv = %x\r\n", spi_send_byte(0x56));Delay500ms();Delay500ms();Delay500ms();Delay500ms();}}

相关推荐

相关文章