在官方的例程的基础上进行了简单修改,SPI0以主机模式工作,发送16字节的数据。代码如下:
#include "CH58x_common.h"
// LED 接在 PB4
#define LED_PIN GPIO_Pin_4
__attribute__((aligned(4))) UINT8 spiBuff[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
__attribute__((aligned(4))) UINT8 spiBuffrev[16];
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();
}
int main()
{
UINT8 i;
SetSysClock(CLK_SOURCE_PLL_60MHz);
/* 配置串口调试 */
DebugInit();
PRINT("Start @ChipID=%02X\n", R8_CHIP_ID);
// 设置指示LED
GPIOB_SetBits(LED_PIN);
GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA);
/* 主机模式 */
PRINT("1.spi0 mul master mode send data ...\n");
DelayMs(100);
/* SPI 0 */
GPIOA_SetBits(GPIO_Pin_12);
GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
SPI0_MasterDefInit();
while(1) {
// FIFO 连续发送
GPIOB_SetBits(LED_PIN);
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterTrans(spiBuff, 16);
GPIOA_SetBits(GPIO_Pin_12);
GPIOB_ResetBits(LED_PIN);
//DelayMs(2);
DelayUs(10);
// DMA 连续发送
GPIOB_SetBits(LED_PIN);
GPIOA_ResetBits(GPIO_Pin_12);
SPI0_MasterDMATrans(spiBuff, 16);
GPIOA_SetBits(GPIO_Pin_12);
GPIOB_ResetBits(LED_PIN);
DelayUs(20);
}
}上记代码中分别以FIDO和DMA两种方式发送16字节数据。从逻辑分析仪获得的时序数据如下:

从时序上看,FIFO方式下,发送花费27μS; DMA方式下,发送花费12.8μS;明显DMA方式的发送更快。SPI的时钟周期SCK是一样的,所以时间上的主要区别在于相邻字节发送的时间间隔(是程序处理代码产生的)上了。前者间隔为970nS,后者70nS。
配置SPI0 的函数:
/*********************************************************************
* @fn SPI0_MasterDefInit
*
* @brief 主机模式默认初始化:模式0+3线全双工+8MHz
*
* @param none
*
* @return none
*/
void SPI0_MasterDefInit(void) {
R8_SPI0_CLOCK_DIV = 4; // 主频时钟4分频
R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_SCK_OE;
R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF; // 访问BUFFER/FIFO自动清除IF_BYTE_END标志
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE; // 不启动DMA方式
}SPI0外设只用了MOSI和SCK,SCS由外部程序控制。
FIFO方式下的发送函数:
/*********************************************************************
* @fn SPI0_MasterTrans
*
* @brief 使用FIFO连续发送多字节
*
* @param pbuf - 待发送的数据内容首地址
* @param len - 请求发送的数据长度,最大4095
*
* @return none
*/
void SPI0_MasterTrans(uint8_t *pbuf, uint16_t len) {
uint16_t sendlen;
sendlen = len;
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; // 设置数据方向为输出
R16_SPI0_TOTAL_CNT = sendlen; // 设置要发送的数据长度
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
while(sendlen) {
if(R8_SPI0_FIFO_COUNT < SPI_FIFO_SIZE) {
R8_SPI0_FIFO = *pbuf;
pbuf++;
sendlen--;
}
}
while(R8_SPI0_FIFO_COUNT != 0); // 等待FIFO中的数据全部发送完成
}DMA下的发送函数:
/*********************************************************************
* @fn SPI0_MasterDMATrans
*
* @brief DMA方式连续发送数据
*
* @param pbuf - 待发送数据起始地址,需要四字节对其
* @param len - 待发送数据长度
*
* @return none
*/
void SPI0_MasterDMATrans(uint8_t *pbuf, uint16_t len) {
R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
R16_SPI0_DMA_BEG = (uint32_t)pbuf; // DMA用的缓冲区
R16_SPI0_DMA_END = (uint32_t)(pbuf + len);
R16_SPI0_TOTAL_CNT = len;
R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END | RB_SPI_IF_DMA_END;
R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE; // 启动DMA方式
}如果不想使用FIFO和DMA方式发送,可以使用函数
发送单字节数据。
我要赚赏金
