前言:
代码参考为首字节模式和数据流模式,均使用DMA,建议使用数据流DMA。
一、数据流/首字节收发代码参考
数据流流程:
- 主机定时器1ms间隔发送;
- 从机接收数据;
- 从机填入发送数据到DMA并通知主机接收;
- 主机DMA接收数据;
首字节流程:
- 主机定时器1ms间隔发送;
- 从机首字节接收并DMA接收完整数据;
- 从机DMA发送数据并通知主机接收;
- 主机DMA接收数据;
主机收发代码:
#include "CH59x_common.h"
#define FSTMODE 0
__attribute__((aligned(4))) UINT8 tx_buff[32] ={0x1,0x55,0x2,0x55,0x3,0x55,0x4,0x55,0x5,0x55,
0x1,0x55,0x2,0x55,0x3,0x55,0x4,0x55,0x5,0x55,
0x1,0x55,0x2,0x55,0x3,0x55,0x4,0x55,0x5,0x55,
0x1,0x55};
__attribute__((aligned(4))) UINT8 rx_buff[32];
uint8_t tx_len[60] = {0};
volatile uint8_t buf_judge[10];
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();
UART1_BaudRateCfg(1500000);
}
VOID SPI_Init(){
GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);/*用于从机通知主机提供时钟,从机准备发送数据*/
GPIOA_ITModeCfg(GPIO_Pin_4, GPIO_ITMode_FallEdge);
PFIC_EnableIRQ(GPIO_A_IRQn);
GPIOA_SetBits(GPIO_Pin_12);
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU);
SPI0_MasterDefInit();
SPI0_CLKCfg(4);
PFIC_EnableIRQ(SPI0_IRQn);
tx_len[0] = sizeof(tx_buff);
printf("tx_playload[0]:%d\n", tx_len[0]);
for (uint8_t i=0; i<sizeof(tx_buff); i++)
{
tx_len[1+i] = tx_buff[i];
}
PRINT("SPI0 Master Init\n");
}
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
DebugInit();/* 配置串口调试 */
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
TMR0_TimerInit(FREQ_SYS / 1000); // 设置定时时间 1ms
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
PFIC_EnableIRQ(TMR0_IRQn);
while(1){
if(buf_judge[0] != 0){
printf("%x %x\n",buf_judge[0], buf_judge[1]);
buf_judge[0] = 0;
}
}
}
__INTERRUPT
__HIGH_CODE
void SPI0_IRQHandler(void)
{
if(R8_SPI0_INT_FLAG & RB_SPI_IF_DMA_END)
{
if(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR)
{
GPIOA_SetBits(GPIO_Pin_12);
buf_judge[0] = rx_buff[30];
buf_judge[1] = rx_buff[31];
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
R16_SPI0_DMA_BEG = 0x3300; //更改DMA地址,出中断
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END|RB_SPI_IF_CNT_END;
R8_SPI0_INTER_EN &=~ (RB_SPI_IE_DMA_END|RB_SPI_IE_CNT_END);
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
}
if(!(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR))//主机发送
{
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END;
}
}
if((R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END)&&(!(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR)))
{
GPIOA_SetBits(GPIO_Pin_12);
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
R16_SPI0_DMA_BEG = 0x4300; //更改DMA地址,出中断
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END|RB_SPI_IF_CNT_END;
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R8_SPI0_INTER_EN &=~ (RB_SPI_IE_DMA_END|RB_SPI_IE_CNT_END);
}
}
__INTERRUPT
__HIGH_CODE
void GPIOA_IRQHandler(void)
{
GPIOA_ClearITFlagBit(GPIO_Pin_4);
GPIOA_ResetBits(GPIO_Pin_12);
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = ((uint32_t)rx_buff);//从机先填DMA,主机再接收
R16_SPI0_DMA_END = ((uint32_t)rx_buff+32);
R16_SPI0_TOTAL_CNT = 32;
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
}
__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler(void) // TMR0 定时中断
{
if(TMR0_GetITFlag(TMR0_3_IT_CYC_END))
{
TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
GPIOA_ResetBits(GPIO_Pin_12);
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
#if FSTMODE
R16_SPI0_DMA_BEG = (uint32_t)tx_len;
R16_SPI0_DMA_END = (uint32_t)(tx_len + (1+sizeof(tx_buff)));
R16_SPI0_TOTAL_CNT = (1+sizeof(tx_buff));
#else
R16_SPI0_DMA_BEG = (uint32_t)tx_buff;
R16_SPI0_DMA_END = (uint32_t)(tx_buff+32);
R16_SPI0_TOTAL_CNT = 32;
#endif
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
}
}
从机收发代码:
#include "CH59x_common.h"
#define FSTMODE 0
__attribute__((aligned(4))) UINT8 tx_buff[32]={0x1,0xaa,0x2,0xaa,0x3,0xaa,0x4,0xaa,0x5,0xaa,
0x1,0xaa,0x2,0xaa,0x3,0xaa,0x4,0xaa,0x5,0xaa,
0x1,0xaa,0x2,0xaa,0x3,0xaa,0x4,0xaa,0x5,0xaa,
0x1,0xaa,};
__attribute__((aligned(4))) UINT8 rx_buff[32];
volatile uint8_t buf_judge[10];
volatile uint8_t len = 0;
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();
UART1_BaudRateCfg(1500000);
}
VOID SPI_Init(){ /* 设备模式 */
GPIOA_SetBits(GPIO_Pin_4);//PA4用于触发主机中断
GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeOut_PP_5mA);
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeIN_PU);/*SPI0 GPIOInit*/
GPIOA_ModeCfg(GPIO_Pin_14, GPIO_ModeIN_PU);
GPIOA_SetBits(GPIO_Pin_15);
GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeOut_PP_5mA);
#if FSTMODE
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_FST_BYTE;
PFIC_EnableIRQ(SPI0_IRQn);
#else
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MODE_SLAVE;
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 ;
R16_SPI0_DMA_BEG = (UINT32)(rx_buff);
R16_SPI0_DMA_END = (UINT32)((rx_buff)+32);
R16_SPI0_TOTAL_CNT = 32;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END;
PFIC_EnableIRQ(SPI0_IRQn);
#endif
PRINT("SPI0 Slave Init\n");
}
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
DebugInit();
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
SPI_Init();
while(1){
if(buf_judge[0] != 0){
printf("%x %x\n", buf_judge[0], buf_judge[1]);
buf_judge[0] = 0;
}
}
}
#if FSTMODE
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void SPI0_IRQHandler(void)
{
if((R8_SPI0_INT_FLAG & RB_SPI_IF_FST_BYTE)&&(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR)){ //已接收到首字节
len = R8_SPI0_FIFO;
R16_SPI0_DMA_BEG = (UINT32)(rx_buff);
R16_SPI0_DMA_END = (UINT32)((rx_buff)+len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
R8_SPI0_INTER_EN &= ~RB_SPI_IE_FST_BYTE;
R8_SPI0_INT_FLAG |= RB_SPI_IF_FST_BYTE;//清除单字节传输完成标志位
R8_SPI0_INTER_EN |= RB_SPI_IE_DMA_END ;
R8_SPI0_CTRL_MOD &= ~RB_SPI_SLV_CMD_MOD;
}
if((R8_SPI0_INT_FLAG & RB_SPI_IF_DMA_END)&&(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR))
{
buf_judge[0] = rx_buff[30];
buf_judge[1] = rx_buff[31];
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R8_SPI0_INTER_EN &= ~RB_SPI_IE_FST_BYTE;
R16_SPI0_DMA_BEG = (UINT32)(tx_buff); //从机先填DMA,主机再接收
R16_SPI0_DMA_END = (UINT32)((tx_buff)+32);
R16_SPI0_TOTAL_CNT = 32;
R8_SPI0_INT_FLAG = RB_SPI_IF_DMA_END;//xxx 不要进中断立马清除标志
GPIOA_ResetBits(GPIO_Pin_4);//xxx 从机发送中断通知脚。从机先填DMA,主机再接收
GPIOA_SetBits(GPIO_Pin_4);
}
if((R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END)&&(!(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR)))
{
R16_SPI0_DMA_BEG = 0;//xxx 需要等到主机接收DMA数据完成才可以修改地址,否则主机接收数据会被篡改
R8_SPI0_INT_FLAG |= RB_SPI_IF_CNT_END;
R8_SPI0_CTRL_MOD |= RB_SPI_SLV_CMD_MOD|RB_SPI_FIFO_DIR;
R8_SPI0_INTER_EN = RB_SPI_IE_FST_BYTE;
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}
}
#else
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void SPI0_IRQHandler(void)
{
if((R8_SPI0_INT_FLAG & RB_SPI_IF_DMA_END)&&(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR)){
buf_judge[0] = rx_buff[30];
buf_judge[1] = rx_buff[31];
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (UINT32)(tx_buff); //从机先填DMA,主机再接收
R16_SPI0_DMA_END = (UINT32)((tx_buff)+32);
R16_SPI0_TOTAL_CNT = 32;
R8_SPI0_INT_FLAG |= RB_SPI_IF_DMA_END;//xxx 不要进中断立马清除标志
GPIOA_ResetBits(GPIO_Pin_4);//xxx 从机发送中断通知脚。从机先填DMA,主机再接收
GPIOA_SetBits(GPIO_Pin_4);
}
if((R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END)&&(!(R8_SPI0_CTRL_MOD&RB_SPI_FIFO_DIR))){
R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (UINT32)(rx_buff);
R16_SPI0_DMA_END = (UINT32)((rx_buff)+32);
R16_SPI0_TOTAL_CNT = 32;
R8_SPI0_INT_FLAG |= RB_SPI_IF_CNT_END;
}
}
#endif
二、波形参考:
三、注意点
标签:DMA,SPI0,59x,R8,SPI,CH58x,RB,GPIO From: https://www.cnblogs.com/gscw/p/18374437