这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【CH582M】CH582M的SPI外设(3)

共1条 1/1 1 跳转至

【CH582M】CH582M的SPI外设(3)

专家
2026-08-24 11:33:05     打赏

在官方的例程的基础上进行了简单修改,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字节数据。从逻辑分析仪获得的时序数据如下:

image.png

 从时序上看,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方式发送,可以使用函数

void SPI1_MasterSendByte(uint8_t d)

发送单字节数据。





关键词: CH582M     SPI    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]