华大HC32F460 SPI+DMA通信实验代码详解

这篇具有很好参考价值的文章主要介绍了华大HC32F460 SPI+DMA通信实验代码详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

声明:以下内容均为本人学习心得。

一、基础知识。

华大HC32F460 提供的SPI是4线式和3线式。搭载4个通道的串行外设接口,支持高速全双工串行同步传输。

4线式:SCK、MOSI、MISO、SS0~SS3。3线式:SCK、MOSI、MISO。

SPI数据发送时:传送数据先进入发送缓冲器(TX_BUFF),再将TX_BUFF的数据复制到移位寄存器(shifter),shifter依次发出数据;SPI数据接受时,数据从shifter依次移入,移入完成后再将shifter的数据复制到接收缓冲器(RX_BUFF)。数据传输时,根据移位顺序控制位SPI_CFG2.LSBF和奇偶校验控制位SPI_CR1.PAE的设置分4种情况:

  1. MSB先传,奇偶校验无效。
  2. LSB先传,奇偶校验无效。
  3. MSB先传,奇偶校验有效时。
  4. LSB先传,奇偶校验有效时。

传送格式:

  1. CPHA=0的情况,当SPI_CFG2.CPHA位为0时,SPI在SCK的奇数边沿进行数据采样,偶数边沿进行数据更新。
  2. CPHA=1的情况,当SPI_CFG2.CPHA位为1时,SPI在SCK的奇数边沿进行数据更新,偶数边沿进行数据采样。

通信方式:

  1. 全双工同步串行通信方式

当SPI_CR1.TXMDS位为“0”时,SPI运行在全双工同步串行通信方式。

注意的是:传输结束时,如果接收数据缓冲寄存器为空,SPI将会把接收到的数据从移位寄存器复制到接收数据缓冲寄存器中,接收数据缓冲寄存器满的标志位被置成1(RDFF),并产生一个接收数据满的中断请求(SPRI)。 如果接收数据缓冲寄存器还保持着上次收到的数据而没有被系统读取,SPI会将数据过载标志位置成1,本次数据接收无效,接收移位寄存器中的数据将被丢弃。

  1. 只进行发送通信方式

当SPI_CR1.TXMDS位为“1”时,SPI运行在只发送通信方式。

SPI主机模式的初始化:

①设置通信配置寄存器1(SPI_CFG1),包括有波特率的设定,使用帧数的设定,各种迟延时间的设定等。

②设置通信配置寄存器2(SPI_CFG2),包括有SS电平设定,数据移位顺序设定,各种延迟的允许位的设定,数据格式及时钟极性相位的设定等。

③如需要使用中断,请设置系统的中断寄存器。

④如需要使用DMA,请设置DMA的相关寄存器。

⑤设定输入输出管脚。

⑥设定SPI控制寄存器SPI_CR1,包括有模式及运行方式的设定,自诊断功能的设定,奇偶校验的设定等。

⑦确认SPI_CR1寄存器的设置。

⑧清除各种标志位。

⑨设置中断许可位

⑩将控制寄存器SPI_CR1的SPE位设置成1,动作开始。

SPI从机模式的初始化:

①设置通信配置寄存器1(SPI_CFG1),包括使用帧数的设定。

②设置通信配置寄存器2(SPI_CFG2),包括有传输速率、数据格式及时钟极性相位的设定等。

③如需要使用中断,请设置系统的中断寄存器。

④如需要使用DMA,请设置DMA的相关寄存器。

⑤设定输入输出管脚。

⑥设定SPI控制寄存器SPI_CR1,包括有模式及运行方式的设定,自诊断功能的设定,奇偶校验的设定等。

⑦确认SPI_CR1寄存器的设置。

⑧清除各种标志位。

⑨设置中断许可位

⑩将控制寄存器SPI_CR1的SPE位设置成1,动作开始。

SPI作为主机时的数据传送处理流程:

①等待数据发送缓冲寄存器空的中断或通过轮询方式确认数据发送缓冲寄存器处于空状态。

②向数据寄存器SPI_DR写入要发送的数据。

③重复①②步骤直到最后一个数据发送完成。

④将发送数据寄存器空中断的允许位TXIE清零,同时将SPI闲置状态中断允许位IDIE设为1。

⑤发送SPI闲置状态中断。

⑥将SPE置0,停止SPI动作,同时将IDIE清零。

数据接收处理流程:

①等待数据接收缓冲寄存器空的中断或通过轮询方式确认数据接收缓冲寄存器处于满状态。

②通过访问SPI_DR从接收缓冲寄存器读取数据

③重复①②步骤直到最后一个接收数据被读取。

④将数据接收缓冲寄存器满的中断允许位RXIE清零。

通信错误处理流程:

①等待通信错误中断或者通过轮询方式确认通信错误标志位(MODFERF/OVRERF/UDRERF/PERF)被置成1。

②确认SS0状态,排除模式故障错误。

③将SPE清零,停止SPI动作。

④将所有SPI中断允许位清零,屏蔽SPI中断。

⑤通过错误标志位确定通信错误种类,进行通讯错误处理。

⑥将错误标志位清零。

⑦启动SPI,重新开始通信。

二、实验代码

实验样例配置通过宏开关选择主机或从机模式,将主机代码下载到一块板子,从机代码下载到另一块板子,通过排线将两块板子的SPI接口相连接,主机按下按键K2,触发一次数据收发,主机和从机对收到的数据和发送的数据进行比较,相同的LED_BLUE亮,不同则LED_RED亮。

设置宏:EXAMPLE_SPI_MASTER_SLAVE = SPI_MASTER为主机模式。

              EXAMPLE_SPI_MASTER_SLAVE = SPI_SLAVE为从机模式。

①各参数配置

/* unlock/lock peripheral */
#define EXAMPLE_PERIPH_WE               (LL_PERIPH_GPIO | LL_PERIPH_EFM | LL_PERIPH_FCG | \
                                         LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM)
#define EXAMPLE_PERIPH_WP               (LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_SRAM)

/* Configuration for Example */
#define EXAMPLE_SPI_MASTER_SLAVE        (SPI_MASTER)
#define EXAMPLE_SPI_BUF_LEN             (128UL)  //SPI接收或发送缓存区大小

/* SPI definition */
#define SPI_UNIT                        (CM_SPI1)
#define SPI_CLK                         (FCG1_PERIPH_SPI1)
#define SPI_TX_EVT_SRC                  (EVT_SRC_SPI1_SPTI)//SPI发送中断序号:300
#define SPI_RX_EVT_SRC                  (EVT_SRC_SPI1_SPRI)//SPI接收中断序号:299

/* DMA definition */
#define DMA_UNIT                        (CM_DMA1)
#define DMA_CLK                         (FCG0_PERIPH_DMA1 | FCG0_PERIPH_AOS)
#define DMA_TX_CH                       (DMA_CH0)
#define DMA_TX_TRIG_CH                  (AOS_DMA1_0)

#define DMA_RX_CH                       (DMA_CH1)
#define DMA_RX_INT_CH                   (DMA_INT_TC_CH1)
#define DMA_RX_TRIG_CH                  (AOS_DMA1_1)
#define DMA_RX_INT_SRC                  (INT_SRC_DMA1_TC1)
#define DMA_RX_IRQ_NUM                  (INT006_IRQn)

/* SS = PA7 */
#define SPI_SS_PORT                     (GPIO_PORT_A)
#define SPI_SS_PIN                      (GPIO_PIN_07)
#define SPI_SS_FUNC                     (GPIO_FUNC_42)
/* SCK = PA8 */
#define SPI_SCK_PORT                    (GPIO_PORT_A)
#define SPI_SCK_PIN                     (GPIO_PIN_08)
#define SPI_SCK_FUNC                    (GPIO_FUNC_43)
/* MOSI = PB0 */
#define SPI_MOSI_PORT                   (GPIO_PORT_B)
#define SPI_MOSI_PIN                    (GPIO_PIN_00)
#define SPI_MOSI_FUNC                   (GPIO_FUNC_40)
/* MISO = PC5 */
#define SPI_MISO_PORT                   (GPIO_PORT_C)
#define SPI_MISO_PIN                    (GPIO_PIN_05)
#define SPI_MISO_FUNC                   (GPIO_FUNC_41)

DMA的参数配置就不详细解读了,有不明白的可以去看我的DMA实验代码详解。

对于各个GPIO引脚的功能选择,我们需要查看数据手册的表2-2 Func32~63,里面有具体说明。

②发送、接收缓存区和标志定义

static char u8TxBuf[EXAMPLE_SPI_BUF_LEN] = "SPI Master/Slave example: Communication between two boards!";
static char u8RxBuf[EXAMPLE_SPI_BUF_LEN];
static __IO en_flag_status_t enRxCompleteFlag = RESET;

③SPI串口通信配置

static void SPI_Config(void)
{
    stc_spi_init_t stcSpiInit;
    stc_dma_init_t stcDmaInit;
    stc_irq_signin_config_t stcIrqSignConfig;

    /* Configure Port */
    GPIO_SetFunc(SPI_SS_PORT,   SPI_SS_PIN,   SPI_SS_FUNC);
    GPIO_SetFunc(SPI_SCK_PORT,  SPI_SCK_PIN,  SPI_SCK_FUNC);
    GPIO_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC);
    GPIO_SetFunc(SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNC);

    /* Configuration SPI */
    FCG_Fcg1PeriphClockCmd(SPI_CLK, ENABLE);
    SPI_StructInit(&stcSpiInit);
    stcSpiInit.u32WireMode          = SPI_4_WIRE;
    stcSpiInit.u32TransMode         = SPI_FULL_DUPLEX;
    stcSpiInit.u32MasterSlave       = EXAMPLE_SPI_MASTER_SLAVE;
    stcSpiInit.u32Parity            = SPI_PARITY_INVD;
    stcSpiInit.u32SpiMode        = SPI_MD_1;//在奇数边沿数据发生变化,在偶数边沿进行数据采样
    stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;
    stcSpiInit.u32DataBits          = SPI_DATA_SIZE_8BIT;
    stcSpiInit.u32FirstBit          = SPI_FIRST_MSB;
    stcSpiInit.u32FrameLevel        = SPI_1_FRAME;
    (void)SPI_Init(SPI_UNIT, &stcSpiInit);

    /* DMA configuration */
    FCG_Fcg0PeriphClockCmd(DMA_CLK, ENABLE);
    (void)DMA_StructInit(&stcDmaInit);
    stcDmaInit.u32BlockSize  = 1UL;
    stcDmaInit.u32TransCount = EXAMPLE_SPI_BUF_LEN;
    stcDmaInit.u32DataWidth  = DMA_DATAWIDTH_8BIT;
    /* Configure TX */
    stcDmaInit.u32SrcAddrInc  = DMA_SRC_ADDR_INC;
    stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
    stcDmaInit.u32SrcAddr     = (uint32_t)(&u8TxBuf[0]);
    stcDmaInit.u32DestAddr    = (uint32_t)(&SPI_UNIT->DR);
    if (LL_OK != DMA_Init(DMA_UNIT, DMA_TX_CH, &stcDmaInit)) {
        for (;;) {
        }
    }
    AOS_SetTriggerEventSrc(DMA_TX_TRIG_CH, SPI_TX_EVT_SRC);
    /* Configure RX */
    stcDmaInit.u32IntEn       = DMA_INT_ENABLE;
    stcDmaInit.u32SrcAddrInc  = DMA_SRC_ADDR_FIX;
    stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
    stcDmaInit.u32SrcAddr     = (uint32_t)(&SPI_UNIT->DR);
    stcDmaInit.u32DestAddr    = (uint32_t)(&u8RxBuf[0]);
    if (LL_OK != DMA_Init(DMA_UNIT, DMA_RX_CH, &stcDmaInit)) {
        for (;;) {
        }
    }
    AOS_SetTriggerEventSrc(DMA_RX_TRIG_CH, SPI_RX_EVT_SRC);

    /* DMA receive NVIC configure */
    stcIrqSignConfig.enIntSrc    = DMA_RX_INT_SRC;
    stcIrqSignConfig.enIRQn      = DMA_RX_IRQ_NUM;
    stcIrqSignConfig.pfnCallback = &DMA_TransCompleteCallback;
    (void)INTC_IrqSignIn(&stcIrqSignConfig);
    NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
    NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
    NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);

    /* Enable DMA and channel */
    DMA_Cmd(DMA_UNIT, ENABLE);
    DMA_ChCmd(DMA_UNIT, DMA_TX_CH, ENABLE);
    DMA_ChCmd(DMA_UNIT, DMA_RX_CH, ENABLE);
}

代码中,GPIO_SetFunc(SPI_SS_PORT,   SPI_SS_PIN,   SPI_SS_FUNC); 目的就是把对应的GPIO引脚配置自己想要的功能,类比于STM32中的映射吧。

我们详细讲讲配置SPI的结构体:

typedef struct {
    uint32_t u32WireMode;           /*!< 配置4线或3线模式*/
	uint32_t u32TransMode;          /*!< 传输模式:全双工or只进行发送通信方式*/
    uint32_t u32MasterSlave;        /*!< 设置主机模式or从机模式 */
    uint32_t u32ModeFaultDetect;    /*!< 使能 模式故障错误检测*/
    uint32_t u32Parity;             /*!< 使能 SPI奇偶校验 */
    uint32_t u32SpiMode;            /*!< 配置SPI模式:主机、从机、主机时钟同步、从机时钟同*/
    uint32_t u32BaudRatePrescaler;  /*!< 配置SPI波特率预分频*/
    uint32_t u32DataBits;           /*!< 配置 传输\接收数据长度 */
    uint32_t u32FirstBit;           /*!< 配置开始位是MSB 还是 LSB */
    uint32_t u32SuspendMode;        /*!< SPI通信暂停功能 */
    uint32_t u32FrameLevel;         /*!<  SPI帧数设定位*/
} stc_spi_init_t;

④DMA传输完成回调函数

static void DMA_TransCompleteCallback(void)
{
    enRxCompleteFlag = SET;
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_RX_INT_CH);
}

⑤DMA重装载配置

static void DMA_ReloadConfig(void)
{
    DMA_SetSrcAddr(DMA_UNIT, DMA_TX_CH, (uint32_t)(&u8TxBuf[0]));
    DMA_SetTransCount(DMA_UNIT, DMA_TX_CH, EXAMPLE_SPI_BUF_LEN);
    DMA_SetDestAddr(DMA_UNIT, DMA_RX_CH, (uint32_t)(&u8RxBuf[0]));
    DMA_SetTransCount(DMA_UNIT, DMA_RX_CH, EXAMPLE_SPI_BUF_LEN);
    /* Enable DMA channel */
    DMA_ChCmd(DMA_UNIT, DMA_TX_CH, ENABLE);
    DMA_ChCmd(DMA_UNIT, DMA_RX_CH, ENABLE);
}

这里为啥需要重装载呢,因为传输完一次,DMA指向源地址变了,需要重新回到初始的源地址,即缓存区:TxBuf[0]和RxBuf[0]

⑥主函数

int32_t main(void)
{
    /* Peripheral registers write unprotected */
    LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
    /* Configure BSP */
    BSP_CLK_Init();
    BSP_LED_Init();
    BSP_KEY_Init();
    /* Configure SPI */
    SPI_Config();
    /* Peripheral registers write protected */
    LL_PERIPH_WP(EXAMPLE_PERIPH_WP);

    for (;;) {
        /* Wait key trigger in master mode */
#if (EXAMPLE_SPI_MASTER_SLAVE == SPI_MASTER)
        while (RESET == BSP_KEY_GetStatus(BSP_KEY_2)) {
        }
#endif
        enRxCompleteFlag = RESET;
        memset(u8RxBuf, 0, EXAMPLE_SPI_BUF_LEN);
        DMA_ReloadConfig();
        /* Enable SPI */
        SPI_Cmd(SPI_UNIT, ENABLE);
        /* Waiting for completion of reception */
        while (RESET == enRxCompleteFlag) {
        }
        /* Disable SPI */
        SPI_Cmd(SPI_UNIT, DISABLE);

        /* Compare u8TxBuf and u8RxBuf */
        if (0 == memcmp(u8TxBuf, u8RxBuf, EXAMPLE_SPI_BUF_LEN)) {
            BSP_LED_On(LED_BLUE);
            BSP_LED_Off(LED_RED);
        } else {
            BSP_LED_On(LED_RED);
            BSP_LED_Off(LED_BLUE);
        }
#if (EXAMPLE_SPI_MASTER_SLAVE == SPI_MASTER)
        /* Wait for the slave to be ready */
        DDL_DelayMS(10U);
#endif
    }
}

通过while (RESET == BSP_KEY_GetStatus(BSP_KEY_2))  来判断按键K2是否按下,按下为低电平,触发SPI通信。

        enRxCompleteFlag = RESET;
        memset(u8RxBuf, 0, EXAMPLE_SPI_BUF_LEN);
        DMA_ReloadConfig();

这3句目的是为了初始化 接收缓存区,如果一开始接收缓存区有数据,则SPI会触发 模式错误。

实验代码讲解到此结束,有什么疑问可以私信我~文章来源地址https://www.toymoban.com/news/detail-676275.html

到了这里,关于华大HC32F460 SPI+DMA通信实验代码详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GD32F103 硬件SPI通信

    SPI既可以做主机也可以做从机。 当做主机时。MOSI,SCK,CS都是作为输出。 而作为从机时。MOSI,SCK,CS都是作为输入。  所以SPI的硬件电路应该实现这样的功能。 1. GD32框图 如下图做主机的数据流向:   如下图做从机的数据流向:    2. STM32框图  通过一些寄存器的配置来控制

    2024年02月02日
    浏览(42)
  • STM32开发(十)STM32F103 通信 —— SPI通信编程详解

    👈《上一篇》  🏡《主目录》  👉《下一篇》 本实验通过STM32F103 的SPI功能,实现对W25Q64JVSSIQ (Flash芯片)芯片擦除,读数据,写数据等操作。 本实验内容知识点: 1、SPI通信协议介绍 2、

    2024年02月07日
    浏览(47)
  • 基于STM32F103C8T6的HC-06蓝牙通信

    如果朋友们 遇到了如下问题 ,可以仔细借鉴本文章和另一篇专门讲解 蓝牙通信问题 的文章,一定能够解决你在蓝牙通信时遇到的诸多困难 1.在调试蓝牙模块AT指令时无返回值 2.身边 无USB转TTL模块 可以直接调试蓝牙模块(本人就是由于无模块花了了整整一天才调试成功)

    2024年02月03日
    浏览(61)
  • STM32F103单片机通过SPI全双工通信协议与W25Q64(FLASH)进行通信【串行同步通信(数据线与时钟线配合),(一主多从模式)】附相关驱动代码详解

    1.W25Qxx系列是一种低成本、小型化、使用简单的 非易失性存储器 ,常应用于数据存储、字库存储、固件程序存储等场景 2.存储介质: Nor Flash(闪存) 3.时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI) 4.存储容量(24位地址): W25Q40: 4Mbit / 512KByte W25Q80: 8Mbit / 1MByte W25Q16: 16

    2024年04月13日
    浏览(59)
  • DMA技术在STM32中优化UART、SPI和I2C通信性能的研究与实现

    DMA(Direct Memory Access,直接存储器访问)技术可以在STM32微控制器上优化UART、SPI和I2C等通信性能。 DMA可以实现数据的高速传输,减轻CPU的负担,提高系统性能。在本篇文章中,我将探讨DMA技术在STM32中优化这些通信协议的研究和实现。 一、DMA工作原理 DMA可以实现外设与存储器

    2024年01月20日
    浏览(40)
  • 【STM32】BLDC驱动&控制开发笔记 | 07_SPI通信测试 - STM32F407用SPI配置DRV8323驱动芯片

    最近在埋头搞STM32 + 无刷直流电机控制,想实现用自己的STM32F407VGT6芯片板子,外加一块驱动板(目前选用到TI的DRV8302或者DRV8323驱动芯片),搞定电机驱动,最后实现比较好的控制效果。如果不是同一块芯片的同学也不用急着走,大体上都是可借鉴哒~ 本文主要实现使用SPI通信

    2024年02月08日
    浏览(50)
  • 【DRV8323】电机驱动芯片寄存器配置指南,通过STM32F407的SPI通信配置

    笔者计划使用一块使用到STM32F407控制芯片与DRV8323s驱动芯片的板子,驱动BLDC。了解到需要使用SPI通信来配置DRV8323s驱动芯片,配置过程中涉及DRV8323数据手册中提及的几个寄存器,故写此文做个记录。 另外,DRV8323芯片和DRV8302、DRV8303、DRV8353都有极大的相似之处,可以相互参考

    2024年02月02日
    浏览(59)
  • 【正点原子STM32连载】 第四十三章 SPI实验 摘自【正点原子】APM32F407最小系统板使用指南

    1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html## 本章将介绍使用APM32F407驱动板载的NOR Flash进行读写操作。通过本章的学习,读者将学习到使用SPI驱

    2024年02月08日
    浏览(60)
  • STM32F429IGT6使用CubeMX配置SPI通信(W25Q256芯片)

    1、硬件电路 需要系统性的看一下W25Q256芯片手册  2、设置RCC,选择高速外部时钟HSE,时钟设置为180MHz 3、配置SPI 4、生成工程配置   5、读写流程图 5、相关代码 6、实验现象 没有问题!

    2024年02月12日
    浏览(44)
  • 正点原子stm32F407学习笔记5——串口通信实验

    上位机给开发板发送数据,开发板将收到的数据发回给上位机 串口设置的一般步骤可以总结为如下几个步骤: 串口时钟使能,GPIO 时钟使能。 设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。 GPIO 初始化设置:要设置模式为复用功能。 串口参数初始化:设置波特率,字长,奇

    2024年02月06日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包