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 MSB FALSE //spi從最高位開始傳輸
#define LSB TRUE //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 : DIO12
MSB, //高位開始傳輸
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 MSB FALSE //spi從最高位開始傳輸
#define LSB TRUE //spi從最低位開始傳輸
uint8 TxBuff[10];
uint8 RxBuff[10];
PUBLIC void vSPI_Slave_Init()
{
bAHI_SpiSlaveEnable(FALSE, //SPISMISO : DIO13, SPISMOSI : DIO12
MSB, //高位開始傳輸
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_S0 0x04
#define SPI_S1 0x08
#define SPIF 0x80 //SPSTAT.7
#define WCOL 0x40 //SPSTAT.6
#define SSIG 0x80 //SPCTL.7
#define SPEN 0x40 //SPCTL.6
#define DORD 0x20 //SPCTL.5
#define MSTR 0x10 //SPCTL.4
#define CPOL 0x08 //SPCTL.3
#define CPHA 0x04 //SPCTL.2
#define SPDHH 0x00 //CPU_CLK/4
#define SPDH 0x01 //CPU_CLK/16
#define SPDL 0x02 //CPU_CLK/64
#define SPDLL 0x03 //CPU_CLK/128
sbit SS = P1 ^ 2; //SPI_1的SS腳
void InitSPI_1(void)
{
ACC = P_SW1; //切換到第一組SPI
ACC &= ~(SPI_S0 | SPI_S1); //SPI_S0=0 SPI_S1=0
P_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();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/230359.html
標籤:其他
