CH58xSPI0中断DMA
前言:
本文针对不常使用的SPI方式使用提供参考,结合SPI中断/DMA/首字节命令模式。
流程:
- 主机发送数据时首字节配置为待发送数据的长度;
- 从机使能SPI中断;
- 在进入中断后配置DMA接收数据。
代码:
主机发送代码参考:
#if 1
uint8_t string[13] = "HelloWorld!!";
uint8_t tx_playload[128] = {0};
/* SPI 0 */
GPIOA_SetBits(GPIO_Pin_12);
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
SPI0_MasterDefInit();
tx_playload[0] = sizeof(string);
for (i=0; i<sizeof(string); i++)
{
tx_playload[1+i] = string[i];
}
printf("sizeof(string):%d\n", sizeof(string));
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterTrans(tx_playload, (1+sizeof(string))); //传输数据,第一个字节为长度
GPIOA_SetBits(GPIO_Pin_12);
PRINT("END ...\n");
while(1);
#endif
从机接收代码参考:
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口调试 */
DebugInit();
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
/* 设备模式 */
PRINT("spi0 mul slave mode \n");
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_ModeIN_PU);
R8_SPI0_CLOCK_DIV = 4; //主频时钟4分频
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR; //SPI 的 FIFO/计数器/中断标志清零
R8_SPI0_CTRL_MOD = RB_SPI_MODE_SLAVE; //SPI0从机模式
R8_SPI0_CTRL_MOD |= RB_SPI_SLV_CMD_MOD; //首字节命令模式
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR; //输入模式,接收数据
R8_SPI0_CTRL_MOD &= ~(RB_SPI_MOSI_OE | RB_SPI_SCK_OE);
R8_SPI0_CTRL_MOD |= RB_SPI_MISO_OE ;
R8_SPI0_INTER_EN |= RB_SPI_IE_FST_BYTE;
PFIC_EnableIRQ(SPI0_IRQn);
while(1);
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void SPI0_IRQHandler(void)
{
uint8_t len = 0;
if (R8_SPI0_INT_FLAG & RB_SPI_IF_FST_BYTE){ //已接收到首字节
R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF;
R8_SPI0_INT_FLAG |= RB_SPI_IF_BYTE_END; //清除单字节传输完成标志位,
len = R8_SPI0_FIFO; //从fifo收到数据,第一个字节为长度
R16_SPI0_DMA_BEG = (UINT32)(rx_buff);
R16_SPI0_DMA_END = (UINT32)((rx_buff)+len);
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
PRINT("Len:%d\n", len);
PRINT("rx_buff:%X\n", ((UINT32)rx_buff&0xffff));
}
if(R8_SPI0_INT_FLAG & RB_SPI_IF_DMA_END)
{
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END; //清除DMA完成标志位
PRINT("SPI_Rec:%s\n", rx_buff);
R16_SPI0_DMA_BEG = 10; //更改DMA地址,出中断
R16_SPI0_DMA_END = 11;
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}
R8_SPI0_INT_FLAG |= 0xff;
}
中断DMA接收数据(此部分代码存在问题,无法接收到首字节,有空验证)
#include "CH58x_common.h"
void DebugInit(void)
{
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
__attribute__((aligned(4))) UINT8 rx_buff[25];
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口调试 */
DebugInit();
/* 设备模式 */
PRINT("1.spi0 mul slave mode \n");
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_ModeIN_PU);
R8_SPI0_CLOCK_DIV = 4; // 主频时钟4分频
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MODE_SLAVE;
R8_SPI0_CTRL_MOD |= RB_SPI_SLV_CMD_MOD;
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR; //输入模式,接收数据
R8_SPI0_CTRL_MOD &= ~(RB_SPI_MOSI_OE | RB_SPI_SCK_OE);
R8_SPI0_CTRL_MOD |= RB_SPI_MISO_OE ;
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END ;
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
PFIC_EnableIRQ(SPI0_IRQn);
while(1);
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void SPI0_IRQHandler(void)
{
if(R8_SPI0_INT_FLAG & RB_SPI_IF_DMA_END)
{
R16_SPI0_DMA_BEG = (UINT32)(rx_buff);
printf("Len:%d, RCV:%s\n", strlen(rx_buff), rx_buff);
R16_SPI0_DMA_BEG = 10; //更改DMA地址,出中断
R16_SPI0_DMA_END = 11;
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END;
}
}