chejia12

  • 2023-11-30
  • 发表了主题帖: 先楫半导体HPM5361EVK DMA

    # 4.dma ## DMAMUX DMAMUX其实就是DMA控制器前一级的多路选择器,有了这个选择器就不用再像F1,F4系列那样每个通道(数据流)要**固定选择指定的外设**,有了多路选择器就可以**任意选择**,外设**使用DMA方式时无需再选择指定的DMA通道(数据流),任意通道(数据流)都可以** HDMA 有 32 个 DMA 请求输入信号,这些 DMA 的请求源来自 DMA 请求路由器(DMAMUX)。 可选的请求源 ```c #define HPM_DMA_SRC_GPTMR0_0                               (0x0UL) #define HPM_DMA_SRC_GPTMR0_1                               (0x1UL) #define HPM_DMA_SRC_GPTMR0_2                               (0x2UL) #define HPM_DMA_SRC_GPTMR0_3                               (0x3UL) #define HPM_DMA_SRC_GPTMR1_0                               (0x4UL) #define HPM_DMA_SRC_GPTMR1_1                               (0x5UL) #define HPM_DMA_SRC_GPTMR1_2                               (0x6UL) #define HPM_DMA_SRC_GPTMR1_3                               (0x7UL) #define HPM_DMA_SRC_GPTMR2_0                               (0x8UL) #define HPM_DMA_SRC_GPTMR2_1                               (0x9UL) #define HPM_DMA_SRC_GPTMR2_2                               (0xAUL) #define HPM_DMA_SRC_GPTMR2_3                               (0xBUL) #define HPM_DMA_SRC_GPTMR3_0                               (0xCUL) #define HPM_DMA_SRC_GPTMR3_1                               (0xDUL) #define HPM_DMA_SRC_GPTMR3_2                               (0xEUL) #define HPM_DMA_SRC_GPTMR3_3                               (0xFUL) #define HPM_DMA_SRC_LIN0                                   (0x10UL) #define HPM_DMA_SRC_LIN1                                   (0x11UL) #define HPM_DMA_SRC_LIN2                                   (0x12UL) #define HPM_DMA_SRC_LIN3                                   (0x13UL) #define HPM_DMA_SRC_UART0_RX                               (0x14UL) #define HPM_DMA_SRC_UART0_TX                               (0x15UL) #define HPM_DMA_SRC_UART1_RX                               (0x16UL) #define HPM_DMA_SRC_UART1_TX                               (0x17UL) #define HPM_DMA_SRC_UART2_RX                               (0x18UL) #define HPM_DMA_SRC_UART2_TX                               (0x19UL) #define HPM_DMA_SRC_UART3_RX                               (0x1AUL) #define HPM_DMA_SRC_UART3_TX                               (0x1BUL) #define HPM_DMA_SRC_UART4_RX                               (0x1CUL) #define HPM_DMA_SRC_UART4_TX                               (0x1DUL) #define HPM_DMA_SRC_UART5_RX                               (0x1EUL) #define HPM_DMA_SRC_UART5_TX                               (0x1FUL) #define HPM_DMA_SRC_UART6_RX                               (0x20UL) #define HPM_DMA_SRC_UART6_TX                               (0x21UL) #define HPM_DMA_SRC_UART7_RX                               (0x22UL) #define HPM_DMA_SRC_UART7_TX                               (0x23UL) #define HPM_DMA_SRC_I2C0                                   (0x24UL) #define HPM_DMA_SRC_I2C1                                   (0x25UL) #define HPM_DMA_SRC_I2C2                                   (0x26UL) #define HPM_DMA_SRC_I2C3                                   (0x27UL) #define HPM_DMA_SRC_SPI0_RX                                (0x28UL) #define HPM_DMA_SRC_SPI0_TX                                (0x29UL) #define HPM_DMA_SRC_SPI1_RX                                (0x2AUL) #define HPM_DMA_SRC_SPI1_TX                                (0x2BUL) #define HPM_DMA_SRC_SPI2_RX                                (0x2CUL) #define HPM_DMA_SRC_SPI2_TX                                (0x2DUL) #define HPM_DMA_SRC_SPI3_RX                                (0x2EUL) #define HPM_DMA_SRC_SPI3_TX                                (0x2FUL) #define HPM_DMA_SRC_CAN0                                   (0x30UL) #define HPM_DMA_SRC_CAN1                                   (0x31UL) #define HPM_DMA_SRC_CAN2                                   (0x32UL) #define HPM_DMA_SRC_CAN3                                   (0x33UL) #define HPM_DMA_SRC_MOT_0                                  (0x34UL) #define HPM_DMA_SRC_MOT_1                                  (0x35UL) #define HPM_DMA_SRC_MOT_2                                  (0x36UL) #define HPM_DMA_SRC_MOT_3                                  (0x37UL) #define HPM_DMA_SRC_MOT_4                                  (0x38UL) #define HPM_DMA_SRC_MOT_5                                  (0x39UL) #define HPM_DMA_SRC_MOT_6                                  (0x3AUL) #define HPM_DMA_SRC_MOT_7                                  (0x3BUL) #define HPM_DMA_SRC_XPI0_RX                                (0x3CUL) #define HPM_DMA_SRC_XPI0_TX                                (0x3DUL) #define HPM_DMA_SRC_DAC0                                   (0x3EUL) #define HPM_DMA_SRC_DAC1                                   (0x3FUL) #define HPM_DMA_SRC_ACMP0                                  (0x40UL) #define HPM_DMA_SRC_ACMP1                                  (0x41UL) ``` ## **MBX** 本产品支持 1 个通讯信箱 MBX,用于进程间通信。处理器可以利用 MBX 互相发送数据,MBX 支持生成中 断。 ## **DMA** **控制器** - 支持 32 个可配置的通道 - 通道支持 2 级优先级配置 - 相同优先级通道使用 Round-Robin 仲裁 - 支持**链式连接多个 DMA 任务** ---- DMA 控制器支持 32 个通道,每个通道都可独立配置数据传输的参数 数据传输后发送响应信号给 DMAMUX,完成硬件握手。 DMA 控制器支持 3 种地址模式:递增模式,递减模式和不变模式 DMA 支持**链式传输**,可以在处理器不介入的情况下,连续完成多个不同配置的传输任务 ## **DMA** **配置使用说明** 以启动某次 DMA 握手模式传输为例,所需要的步骤为: 1. 配置对应通道的寄存器 transize, **总数据量**为 transize x srcwidth; 2. 配置对应通道的寄存器 srcaddr,指向**源数据的起始地址**; 3. 配置对应**通道的寄存器** chanreqctl,包括源数据 DMA 请求选择 srcreqsel 或目的数据 DMA 请求选择 dstreqsel; 4. 配置对应通道的寄存器 dstaddr,指向**目标数据的起始地址**; 5. 如果是**非链式传输**,则配置 llpointer 为 0x0,否则配置为下一链式数据结构的起始地址; 6. 配置对应通道的寄存器 ctrl,包括**优先级 priority 字段、源突发长度 srcburstsize 字段、源数据位宽 sr** **cwidth、目的数据位宽 dstwidth 字段、通道使能字段 enable**; 7. 配置 DMAMUX,**将 srcreqsel 或者 dstreqsel 路由至对应的通道**; 8. 读取的寄存器 inttcsts,**判断**对应通道的传输是否**完成**;

  • 发表了主题帖: 先楫半导体HPM5361EVK时钟

    # 3.时钟 时钟源包括**外部晶振 XTAL、内部 RC 振荡器和锁相环 PLL **等,时钟源能够产生各种不同频率,不同精度的时钟。 功能时钟 CLK_TOP 是对时钟源进行选择和分频后的时钟 系统中有 8 个时钟源,所以每个功能时钟有一个 8 选 1 的多路选择器进行时钟源选择, ### 各功能时钟已预先设置了时钟源选择和分频系数 - ADC 和 DAC 的功能时钟采用两级多路选择结构,用以支持任意个 ADC 或任意个 DAC 同步工作或异步工作 - CLK_TOP_ADCx 和 CLK_TOP_DACx 默认依次选择 CLK_TOP_AHB - 该结构使任意个 ADC 或 DAC 能够以相同的时钟工作或者各自工作在独立的时钟频率。

  • 2023-11-23
  • 发表了主题帖: 先楫半导体HPM5361EVK入门

    # 1.先楫半导体HPM5361EVK入门 ## 1.资料下载和环境搭建 ### 1.1根据论坛的提示下载资料 [【国产高性能运动控制MCU 先楫HPM5361】测评|【国产高性能运动控制MCU 先楫HPM5361】免费试用_电子工程世界 (eeworld.com.cn)](http://bbs.eeworld.com.cn/elecplay/content/eea33c48#F4) ### 2.2下载编译器 [SEGGER - The Embedded Experts - Downloads - Embedded Studio](https://www.segger.com/downloads/embedded-studio) ### 2.3安装Embedded Studio for RISC-V编译器 ### 2.4安装ft2232驱动,该驱动用于mcu调试 完成以后如下图: ## 2.创建工程和下载调试 ### 2.1.打开HPM工程创建工具 ### 2.2创建工程 1. 选择开发板 2. 选择模板工程 3. 生产工程 4. 打开工程 ### 2.3编译工程 ### 2.4.插上条线帽 ### 2.5设置调试串口 ### 2.6连接调试终端 ### 2.7启动调试 ### 2.8调试后 ## 3.其他窗口 ### 1.内存查看 ### 2.终端窗口 ### 3.cpu寄存器观察窗口

  • 2023-11-20
  • 回复了主题帖: 读书入围名单: 《奔跑吧Linux内核(第2版)卷1:基础架构》

    个人信息无误,确认可以完成任务

  • 回复了主题帖: 测评入围名单: 国产高性能运动控制MCU 先楫HPM5361

    个人信息无误,确认可以完成评测计划

  • 2023-11-07
  • 回复了主题帖: 【有奖话题】说一说你觉得最能打的国产充电管理芯片芯片

    我使用过智融的sw3516芯片,这个芯片支持多种手机快充协议,最高支持100w

  • 2023-10-25
  • 发表了主题帖: 《运算放大器参数解析与LTspice应用仿真》读书笔记-核心参数

    # 输入失调电压Vos 在直流信号调理电路中最常见的问题 理想情况之下,Vp=Vn即虚短的概念;实际情况下,Vp!=Vn,这2者的差异就是失调电压; Vos的取值范围时mV~uV,毫伏到微伏 产生的原因:         -        输入级的制造工艺         -        芯片的封装工艺 失调电压的漂移:定义为失调电压因温度和工作时间变化而变化的 ### 失调电压的处理方法: 1. 调节失调电压的调整引脚 2. 在反向放大器中,在同向端提供失调电压的调节电路 3. 在同向放大器中,使用失调电压抵消电路 #         输入失调电流和偏置电流 真实的运放的输入引脚都会吸收少量的电流。 输入偏置电流:同向端和反向端输入电流的均值 输入失调电流:同向端和反向端输入电流之差。 高速放大器的偏置电流可达**十微安** 普通精密放大器的偏置电流约在**纳安** 通常****中子和β剂量计软件开发调试情况**** 偏置电流也随着温度的变化 ## 偏置电流的处理方法 1. 偏置电流需要**有完整的直流回路** 2. 放大器的输入端电阻匹配 3. 选择偏置电流较小的放大器 **总的失调电压是由输入是电压的和偏置电流所致** # 共模抑制比 具有共模输入信号的同向放大电路也需要考虑共模抑制比 **差模增益**:加载于2个输入端之间的信号所获得的增益 **共模增益**:同时加载于2个输入端信号所获得的增益 放大器的差模增益是电路所需要的增益,而共模增益将放大直流噪声。 **共模抑制比**:**差模增益**/**共模增益**=CMRR CMRR(DB) = 20log(CCMR) - **老一代的精密运放的共模抑制比在70-120DB** - **OP07在 100~120DB** - **ADA4077 在 132~150BD** **电阻误差导致使用通用放大器组建的差动放大器和仪表放大器**的共模抑制能力下降。 差动放大器在电路设计中还需要考虑信号的内阻,信号源的内阻越小,电路的共模抑制能力越强;有效降低信号源对共模抑制能力的影响方式是在放大器的输入端**加上1级电压跟随器**。

  • 发表了日志: 《运算放大器参数解析与LTspice应用仿真》读书笔记

  • 发表了主题帖: 《运算放大器参数解析与LTspice应用仿真》读书笔记

    理想运放的主要参数 1 . 开环差模电压增益无限大 2 . 差模输入电阻无限大 3 . 没有输入偏置电流 4 . 没有输入失调电压 5 . 共模抑制比无限大 6 . 输出电阻无限小 7 . -3DB截止频率无线高 8 . 内部没有电压,无电流噪声,不受温度影响 放大器的组成 1 . 输入级:输入阻抗高,共模抑制能力强,噪声抑制能力强,静态电流小 2 . 中间级:放大能力强 3 . 输出级:输出动态范围大,非线性失真小,带负载能力强 运算放大器的基础电路 1.反向放大器 1 . 相位相差180° 2 . g=-(Rf/Rg)*Vi   单电源的反向放大器: 2.同向放大器   3.求和电路   4.积分电路         5.微分电路       6.差动放大器  

  • 2023-08-16
  • 回复了主题帖: 测评颁奖:极海APM32F407 Tiny Board测评活动,+极海礼包给优秀测评者

    个人信息确认无误

  • 2023-07-16
  • 发表了主题帖: 【CW32L052R8T6 】学习笔记05-串口的接收中断+空闲中断

    #空闲中断 串口空闲中断需要操作寄存器,没有对应和函数 ## 空闲中断涉及的知识要点 ## 初始化代码 ```c void bsp_enable_idle() {                 DEBUG_UARTx->CR2_f.TIMCR = 0x3;         DEBUG_UARTx->IER_f.TIMOV=1;         DEBUG_UARTx->TIMARR=0xff;                 } ``` ## 中断处理处理办法 ```c void UART2_IRQHandler() {     uint8_t TxRxBuffer;     if(UART_GetITStatus(DEBUG_UARTx, UART_IT_RC) != RESET)     {         TxRxBuffer = UART_ReceiveData_8bit(DEBUG_UARTx);        // UART_SendData_8bit(DEBUG_UARTx, TxRxBuffer);         UART_ClearITPendingBit(DEBUG_UARTx, UART_IT_RC);     }     //以下就是空闲中断的处理         else if(UART_GetITStatus(DEBUG_UARTx, 0x200) != RESET)     {                         //这里需要重新设置,否则只执行一次接收空闲中断检测                         DEBUG_UARTx->CR2_f.TIMCR = 0x3;                         UART_ClearITPendingBit(DEBUG_UARTx, 0x200);                          bsp_led_blink();     } } ``` ## 实例函数 ### uart_it_idle.h ```c #ifndef __BSP_UART_TI_H_ #define __BSP_UART_TI_H_ #include #include #include "cw32l052_gpio.h" #include "cw32l052_rcc.h" #include "cw32l052_uart.h" //UARTx #define  DEBUG_UARTx                   CW_UART2 #define  DEBUG_UART_CLK                RCC_APB1_PERIPH_UART2 #define  DEBUG_UART_APBClkENx          RCC_APBPeriphClk_Enable1 #define  DEBUG_UART_BaudRate           9600 #define  DEBUG_UART_UclkFreq           8000000 //UARTx GPIO #define  DEBUG_UART_TX_GPIO_CLK           RCC_AHB_PERIPH_GPIOC #define  DEBUG_UART_RX_GPIO_CLK           RCC_AHB_PERIPH_GPIOD #define  DEBUG_UART_TX_GPIO_PORT       CW_GPIOC #define  DEBUG_UART_TX_GPIO_PIN        GPIO_PIN_12 #define  DEBUG_UART_RX_GPIO_PORT       CW_GPIOD #define  DEBUG_UART_RX_GPIO_PIN        GPIO_PIN_2 //GPIO AF #define  DEBUG_UART_AFTX               PC12_AFx_UART2TXD() #define  DEBUG_UART_AFRX               PD02_AFx_UART2RXD() //中断 #define  DEBUG_UART_IRQ                UART2_IRQn void bsp_uart_it_init(void); void bsp_it_send_recv_test(void); #endif ``` ### uart_it_idle.c ```c #include "uart_it.h" #include "led.h" /** * @brief 配置RCC * */ static void RCC_Configuration(void) {     //SYSCLK = HSI = 8MHz = HCLK = PCLK     RCC_HSI_Enable(RCC_HSIOSC_DIV6);     //外设时钟使能     RCC_AHBPeriphClk_Enable(DEBUG_UART_TX_GPIO_CLK, ENABLE);     RCC_AHBPeriphClk_Enable(DEBUG_UART_RX_GPIO_CLK, ENABLE);     DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); } /** * @brief 配置GPIO * */ static void GPIO_Configuration(void) {     GPIO_InitTypeDef GPIO_InitStructure = {0};     //UART TX RX 复用     DEBUG_UART_AFTX;     DEBUG_UART_AFRX;     GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);     GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;     GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure); } /** * @brief 配置UART * */ static void UART_Configuration(void) {     UART_InitTypeDef UART_InitStructure = {0};     UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate;     UART_InitStructure.UART_Over = UART_Over_16;     UART_InitStructure.UART_Source = UART_Source_PCLK;     UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq;     UART_InitStructure.UART_StartBit = UART_StartBit_FE;     UART_InitStructure.UART_StopBits = UART_StopBits_1;     UART_InitStructure.UART_Parity = UART_Parity_No ;     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;     UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;     UART_Init(DEBUG_UARTx, &UART_InitStructure); } /** * @brief 配置NVIC * */ void NVIC_Configuration(void) {     //优先级,无优先级分组     NVIC_SetPriority(DEBUG_UART_IRQ, 0);     //UARTx中断使能     NVIC_EnableIRQ(DEBUG_UART_IRQ); } void enable_idle() {                 DEBUG_UARTx->CR2_f.TIMCR = 0x3;         DEBUG_UARTx->IER_f.TIMOV=1;         DEBUG_UARTx->TIMARR=0xff;                 } void bsp_uart_it_init(void) {     //配置RCC     RCC_Configuration();     //配置GPIO     GPIO_Configuration();     //配置UART     UART_Configuration();                 enable_idle();     //使能UARTx RC中断     UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE);     //配置NVIC     NVIC_Configuration(); } void bsp_it_send_recv_test() {     UART_SendString(DEBUG_UARTx, "\r\nCW32L052 UART Interrupt\r\n"); } int fputc(int ch, FILE* f) {     UART_SendData_8bit(DEBUG_UARTx, ch);     while(UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);     return (ch); } void UART2_IRQHandler() {     uint8_t TxRxBuffer;     if(UART_GetITStatus(DEBUG_UARTx, UART_IT_RC) != RESET)     {         TxRxBuffer = UART_ReceiveData_8bit(DEBUG_UARTx);        // UART_SendData_8bit(DEBUG_UARTx, TxRxBuffer);         UART_ClearITPendingBit(DEBUG_UARTx, UART_IT_RC);     }                                 else if(UART_GetITStatus(DEBUG_UARTx, 0x200) != RESET)     {                         //这里需要重新设置,否则只执行一次接收空闲中断检测                         DEBUG_UARTx->CR2_f.TIMCR = 0x3;                         UART_ClearITPendingBit(DEBUG_UARTx, 0x200);                          bsp_led_blink();     } } ```

  • 发表了主题帖: 【CW32L052R8T6 】学习笔记04-串口中断接收数据

    ## 中断接收串口使用步骤: 1. 设置时钟    1. gpio先关时钟    2. 串口外设时钟    3. 串口的时钟源设置 2. 设置gpio    1. 复用AF    2. TX设置为上拉输出    3. RX 设置为上拉输入 3. 配置串口参数(没有使能的步骤)    1. 波特率    2. 停止位    3. 奇偶校验    4. **采样方式**    5. **传输时钟源及频率**    6. 发送接收使能    7. 硬件流控制 4. 使能串口中断 ‘ UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE);’ 5. 配置中断管理    1. 设置优先级    2. 使能中断    3. 没有**中断分组**的概念 6. 查询发送标志可以判定是否发送结束    1. 查询发送标志为空    2. 为空则可以发送数据 7. 实现接收中断处理函数,接收数据    1. 查看接收非空标志    2. 清除接收非空标志    3. 接收数据     ### 中断 #### 中断主要特性 - 16 个内部异常 - 32 个可屏蔽外部中断 - 4 个可编程的优先级 - 低延时的异常和中断处理 - 支持中断嵌套 - 中断向量表重映射---可以在BootLoader  IAP中使用 #### 中断优先级 - 外部中断可设置 4 级优先级,最高优先级为“0”,最低优先级为“3”,默认值为“0”。 - 当处理器正在执行一个中断处理程序时,如果出现一个**更高优先级**的中断,那么这个中断就被**抢占**。 - 如果出现的 中断的优先级和正在处理的中断的**优先级相同或更低**,这个中断就**不会被抢占**,但是新中断的状态就变为挂起。 - 如果多个挂起的中断具有相同的优先级,**中断编号越小**的挂起中断**优先处理**。 ### 使用官方测试代码的坑: 中断函数文件内部的中断函数名称和启动文件的函数名称不一致,导致串口接收中断后找不到处理函数 ### 测试学习代码 #### uart_it.h ```c #ifndef __BSP_UART_H_ #define __BSP_UART_H_ #include #include #include "cw32l052_gpio.h" #include "cw32l052_rcc.h" #include "cw32l052_uart.h" //UARTx #define  DEBUG_UARTx                   CW_UART2 #define  DEBUG_UART_CLK                RCC_APB1_PERIPH_UART2 #define  DEBUG_UART_APBClkENx          RCC_APBPeriphClk_Enable1 #define  DEBUG_UART_BaudRate           9600 #define  DEBUG_UART_UclkFreq           8000000 //UARTx GPIO #define  DEBUG_UART_TX_GPIO_CLK           RCC_AHB_PERIPH_GPIOC #define  DEBUG_UART_RX_GPIO_CLK           RCC_AHB_PERIPH_GPIOD #define  DEBUG_UART_TX_GPIO_PORT       CW_GPIOC #define  DEBUG_UART_TX_GPIO_PIN        GPIO_PIN_12 #define  DEBUG_UART_RX_GPIO_PORT       CW_GPIOD #define  DEBUG_UART_RX_GPIO_PIN        GPIO_PIN_2 //GPIO AF #define  DEBUG_UART_AFTX               PC12_AFx_UART2TXD() #define  DEBUG_UART_AFRX               PD02_AFx_UART2RXD() #endif ``` #### uart_it.c ```c #include "uart_it.h" /** * @brief 配置RCC * */ static void RCC_Configuration(void) {     //SYSCLK = HSI = 8MHz = HCLK = PCLK     RCC_HSI_Enable(RCC_HSIOSC_DIV6);     //外设时钟使能     RCC_AHBPeriphClk_Enable(DEBUG_UART_TX_GPIO_CLK, ENABLE);     RCC_AHBPeriphClk_Enable(DEBUG_UART_RX_GPIO_CLK, ENABLE);     DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); } /** * @brief 配置GPIO * */ static void GPIO_Configuration(void) {     GPIO_InitTypeDef GPIO_InitStructure = {0};     //UART TX RX 复用     DEBUG_UART_AFTX;     DEBUG_UART_AFRX;     GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);     GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;     GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure); } /** * @brief 配置UART * */ static void UART_Configuration(void) {     UART_InitTypeDef UART_InitStructure = {0};     UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate;     UART_InitStructure.UART_Over = UART_Over_16;     UART_InitStructure.UART_Source = UART_Source_PCLK;     UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq;     UART_InitStructure.UART_StartBit = UART_StartBit_FE;     UART_InitStructure.UART_StopBits = UART_StopBits_1;     UART_InitStructure.UART_Parity = UART_Parity_No ;     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;     UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;     UART_Init(DEBUG_UARTx, &UART_InitStructure); } /** * @brief 配置NVIC * */ void NVIC_Configuration(void) {     //优先级,无优先级分组     NVIC_SetPriority(DEBUG_UART_IRQ, 0);     //UARTx中断使能     NVIC_EnableIRQ(DEBUG_UART_IRQ); } void bsp_uart_it_init(void) {     //配置RCC     RCC_Configuration();     //配置GPIO     GPIO_Configuration();     //配置UART     UART_Configuration();                     //使能UARTx RC中断     UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE);     //配置NVIC     NVIC_Configuration(); } void bsp_it_send_recv_test() {     UART_SendString(DEBUG_UARTx, "\r\nCW32L052 UART Interrupt\r\n"); } int fputc(int ch, FILE* f) {     UART_SendData_8bit(DEBUG_UARTx, ch);     while(UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);     return (ch); } void UART2_IRQHandler() {     uint8_t TxRxBuffer;     if(UART_GetITStatus(DEBUG_UARTx, UART_IT_RC) != RESET)     {         TxRxBuffer = UART_ReceiveData_8bit(DEBUG_UARTx);         UART_SendData_8bit(DEBUG_UARTx, TxRxBuffer);         UART_ClearITPendingBit(DEBUG_UARTx, UART_IT_RC);     } } ```

  • 发表了主题帖: 【CW32L052R8T6 】学习笔记03-串口轮训接收数据

    本帖最后由 chejia12 于 2023-7-16 22:37 编辑 # 串口uart ## 概述 CW32L052 内部集成 3 个通用异步收发器 (UART), - 支持异步全双工、同步半双工和单线半双工模式, - 支持硬件数 据流控和多机通信,还支持 LIN(局域互连网络); - 可编程数据帧结构,可以通过小数波特率发生器提供宽范围 的波特率选择; - 内置定时器模块,支持等**待超时检测、接收空闲检测、自动波特率检测**和通用定时功能。 - UART 控制器工作在双时钟域下,允许在深度休眠模式下进行数据的接收,接收完成中断可以唤醒 MCU 回到运行 模式 ## 主要特性 - 支持**双时钟域驱动**   - 配置时钟 PCLK   - 传输时钟 UCLK - 可编程数据帧结构   - 数据字长:8、9 位,LSB 在前   - 校验位:无校验、奇校验、偶校验   - 停止位长度:1、1.5、2 位 - 16 位整数、4 位小数波特率发生器 - 支持异步全双工、同步半双工、单线半双工 - 支持硬件流控 RTS、CTS - 支持直接内存访问 (DMA) - 支持多机通信,自动地址识别 - 9 个带中断标志的中断源 - **自动波特率检测模式 1/2** - 等待**超时检测 / 接收空闲检测** - 内置定时器模块支持通用定时器功能 - 错误检测:奇偶校验错误、帧结构错误 - **低功耗模式下收发数据,中断唤醒 MCU** - LIN 主模式同步间隔段发送功能和 LIN 从模式同步间隔段检测功能 - 支持长度可配置的同步间隔段发送 - 支持 10/11 位同步间隔段的检测 > *     @arg UART_FLAG_TXBUSY:  发送忙标志 >  *     @arg UART_FLAG_CTSLV:   CTS信号电平状态标志 >  *     @arg UART_FLAG_CTS:     CTS信号变化标志 >  *     @arg UART_FLAG_MATCH:   从机地址匹配标志 >  *     @arg UART_FLAG_PE:      奇偶校验错误标志 >  *     @arg UART_FLAG_FE:      帧结构错误标志 >  *     @arg UART_FLAG_RC:      接收完成标志 >  *     @arg UART_FLAG_TC:      发送完成标志 >  *     @arg UART_FLAG_TXE:     发送缓冲器空标志 ## 轮训串口使用步骤: 1. 设置时钟    1. gpio先关时钟    2. 串口外设时钟    3. 串口的时钟源设置 2. 设置gpio    1. 复用AF    2. TX设置为上拉输出    3. RX 设置为上拉输入 3. 配置串口参数(没有使能的步骤)    1. 波特率    2. 停止位    3. 奇偶校验    4. **采样方式**    5. **传输时钟源及频率**    6. 发送接收使能    7. 硬件流控制 4. 查询发送标志可以判定是否发送结束    1. 查询发送标志为空    2. 为空则可以发送数据 5. 查询接收标志可以判定是否有数据收到    1. 需要的手动清除非空标志    2. 接收数据 系统时钟设置为HSIOSC时钟6分频,8MHz,PCLK、HCLK不分频,PCLK=HCLK=SysClk=8MHz ### 轮训测试代码 #### uart.h ```c #ifndef __BSP_UART_H_ #define __BSP_UART_H_ #include #include #include "cw32l052_gpio.h" #include "cw32l052_rcc.h" #include "cw32l052_uart.h" //UARTx #define  DEBUG_UARTx                   CW_UART2 #define  DEBUG_UART_CLK                RCC_APB1_PERIPH_UART2 #define  DEBUG_UART_APBClkENx          RCC_APBPeriphClk_Enable1 #define  DEBUG_UART_BaudRate           9600 #define  DEBUG_UART_UclkFreq           8000000 //UARTx GPIO #define  DEBUG_UART_TX_GPIO_CLK           RCC_AHB_PERIPH_GPIOC #define  DEBUG_UART_RX_GPIO_CLK           RCC_AHB_PERIPH_GPIOD #define  DEBUG_UART_TX_GPIO_PORT       CW_GPIOC #define  DEBUG_UART_TX_GPIO_PIN        GPIO_PIN_12 #define  DEBUG_UART_RX_GPIO_PORT       CW_GPIOD #define  DEBUG_UART_RX_GPIO_PIN        GPIO_PIN_2 //GPIO AF #define  DEBUG_UART_AFTX               PC12_AFx_UART2TXD() #define  DEBUG_UART_AFRX               PD02_AFx_UART2RXD() #endif ``` #### uart.c ```c #include "uart.h" /** * @brief 配置RCC * */ static void RCC_Configuration(void) {     //SYSCLK = HSI = 8MHz = HCLK = PCLK     RCC_HSI_Enable(RCC_HSIOSC_DIV6);     //外设时钟使能     RCC_AHBPeriphClk_Enable(DEBUG_UART_TX_GPIO_CLK, ENABLE);     RCC_AHBPeriphClk_Enable(DEBUG_UART_RX_GPIO_CLK, ENABLE);     DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); } /** * @brief 配置GPIO * */ static void GPIO_Configuration(void) {     GPIO_InitTypeDef GPIO_InitStructure = {0};     //UART TX RX 复用     DEBUG_UART_AFTX;     DEBUG_UART_AFRX;     GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);     GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;     GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;     GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure); } /** * @brief 配置UART * */ static void UART_Configuration(void) {     UART_InitTypeDef UART_InitStructure = {0};     UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate;     UART_InitStructure.UART_Over = UART_Over_16;     UART_InitStructure.UART_Source = UART_Source_PCLK;     UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq;     UART_InitStructure.UART_StartBit = UART_StartBit_FE;     UART_InitStructure.UART_StopBits = UART_StopBits_1;     UART_InitStructure.UART_Parity = UART_Parity_No ;     UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;     UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;     UART_Init(DEBUG_UARTx, &UART_InitStructure); } /** * @brief 发送8位数组 * * @param UARTx :UARTx外设 *        参数可以是: *           CW_UART1、CW_UART2、CW_UART3、CW_UART4、CW_UART5、CW_UART6 * @param TxBuf :待发送的数组 * @param TxCnt :待发送的数组元素个数 */ static void UART_SendBuf_Polling(UART_TypeDef* UARTx, uint8_t *TxBuf, uint8_t TxCnt) {     while(TxCnt)     {         UART_SendData_8bit(UARTx, *TxBuf);         while(UART_GetFlagStatus(UARTx, UART_FLAG_TXE) == RESET);         TxBuf++;         TxCnt--;     }     while(UART_GetFlagStatus(UARTx, UART_FLAG_TXBUSY) == SET); } /** * @brief 接收8位数组 * * @param UARTx :UARTx外设 *        参数可以是: *           CW_UART1、CW_UART2、CW_UART3、CW_UART4、CW_UART5、CW_UART6 * @param RxBuf :接收Buf * @return uint8_t :接收的字符个数 */ static uint8_t UART_RecvBuf_Polling(UART_TypeDef* UARTx, uint8_t *RxBuf) {     uint8_t RxCnt = 0;     do     {         //等待RC         while(UART_GetFlagStatus(UARTx, UART_FLAG_RC) == RESET);         //清RC         UART_ClearFlag(UARTx, UART_FLAG_RC);         //ERROR: PE or FE         if(UART_GetFlagStatus(UARTx, UART_FLAG_PE|UART_FLAG_FE))         {             UART_ClearFlag(UARTx, UART_FLAG_PE|UART_FLAG_FE);             RxCnt = 0x00;         }         else         {             RxBuf[RxCnt] = UART_ReceiveData_8bit(UARTx);             RxCnt++;         }     }     while(RxBuf[RxCnt-1] != '\n');     return RxCnt; } void bsp_uart_polling_init(void) {     //配置RCC     RCC_Configuration();     //配置GPIO     GPIO_Configuration();     //配置UART     UART_Configuration(); } void bsp_polling_send_recv_test(uint8_t *send_data, uint32_t len) {     UART_SendBuf_Polling(DEBUG_UARTx, send_data, len);     while(1)     {         //轮询收发         len = UART_RecvBuf_Polling(DEBUG_UARTx, send_data);         UART_SendBuf_Polling(DEBUG_UARTx, send_data, len);     } } ```

  • 2023-07-15
  • 回复了主题帖: 【CW32L052R8T6 】学习笔记01-芯片基本信息了解

    火辣西米秀 发表于 2023-7-15 08:32 CW32L052 是基于 eFlash 的单芯片低功耗微控制器,这个 eFlash 是何物
    eFlash工艺(嵌入式闪存):是MCU中必不可少的组成部分,用来存储代码和使用过程中产生的数据,当前制造MCU能达到的制程节点很大一部分原因是受限于eFlash制程工艺。 eFlash控制器由以下模块组成: 1. flash与AHB总线的接口模块(flash_ahb_if):接收AHB总线控制信号,地址信号和数据信号;将地址译码转化成flash地址;配置控制寄存器以配合flash_ctrl模块的控制操作;并且储存flash工作状态到状态寄存器供软件可查。 2. flash控制模块(falsh_ctrl):接收总线地址和命令,完成Flsh的读、写、和擦除操作;

  • 回复了主题帖: 【CW32L052R8T6 】学习笔记01-芯片基本信息了解

    eFlash工艺(嵌入式闪存):是MCU中必不可少的组成部分,用来存储代码和使用过程中产生的数据,当前制造MCU能达到的制程节点很大一部分原因是受限于eFlash制程工艺。 eFlash控制器由以下模块组成: 1. flash与AHB总线的接口模块(flash_ahb_if):接收AHB总线控制信号,地址信号和数据信号;将地址译码转化成flash地址;配置控制寄存器以配合flash_ctrl模块的控制操作;并且储存flash工作状态到状态寄存器供软件可查。 2. flash控制模块(falsh_ctrl):接收总线地址和命令,完成Flsh的读、写、和擦除操作;  

  • 发表了主题帖: 【CW32L052R8T6 】学习笔记02-模板工程点亮LED

    本帖最后由 chejia12 于 2023-7-15 22:02 编辑 # 模板工程点亮LED 芯片默认使用内部HSI作为时钟信号,使用外部HSE需要手动切换 HSIOSC 时钟经过分频后输出 HSI 时钟,分频系数通过内置高频时钟控制寄存器 SYSCTRL_HSI 的 DIV 位域设置, 有效分频系数为 1、2、4、6、8、10、12、14、16,**上电后默认值为 6,所以 HSI 时钟默认频率为 8MHz**。 ## 建立工程 1. 创建工程目录 2. 复制必要的文件到工程目录 3. mdk创建工程 4. mdk添加分组和在分组中添加文件 5. 设置头文件 6. 设置编译器版本,选择下载器,选择MicroLIB 7. 添加LED闪烁代码 8. 编译下载 ## 创建工程目录 ## 复制必要的文件到工程目录 ## mdk创建工程 ## mdk添加分组和在分组中添加文件 1. 添加库文件和main.c 中断文件,启动文件.s 2. 添加cortex-M0相关文件 ## ## 设置头文件 > ..\stdlib\inc ## 添加LED闪烁代码 ```c #include "main.h" void delay(uint32_t tick) {     while (tick )     {         tick--;     } } void assert_failed(uint8_t *file, uint32_t line) { } /*         LED初始化步骤                 1.设置时钟                 2.设置gpio属性                         a. 中断属性                         b. 上下拉属性                         c. 那个引脚                 3.初始化gpio                 4.使用gpio */ int32_t main(void) {     //配置RCC     GPIO_InitTypeDef GPIO_InitStruct = {0};     __RCC_GPIOC_CLK_ENABLE();//     GPIO_InitStruct.IT = GPIO_IT_NONE;     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     GPIO_InitStruct.Pins = GPIO_PIN_10;     GPIO_Init(CW_GPIOC, &GPIO_InitStruct);     while (1)     {         GPIO_TogglePin(CW_GPIOC, GPIO_PIN_10);         delay(0xfffff);     } } ``` ## 编译下载 ## LED硬件 ## LED初始化步骤 1. 设置时钟 2. 设置gpio属性    a.  中断属性    b.  上下拉属性    c.  那个引脚 3. 初始化gpio 4. 使用gpio

  • 2023-07-14
  • 发表了主题帖: 【CW32L052R8T6 】学习笔记01-芯片基本信息了解

    # 芯片简介 ## 产品特性 - 内核:ARM® Cortex®-M0+ - 最高主频 48MHz - 工作温度:-40℃ 至 85℃;工作电压:1.65V 至 5.5V - 存储容量 - 最大 64K 字节 FLASH,数据保持 25 年 @85℃ - 最大 8K 字节 RAM,支持奇偶校验 - 128 字节 OTP 存储器 - CRC 硬件计算单元 - 复位和电源管理   - 低功耗模式(Sleep,DeepSleep)   - 上电和掉电复位(POR/BOR)   - 可编程低电压检测器(LVD) - 时钟管理 - 4MHz ~ 32MHz 晶体振荡器 - 32kHz 低速晶体振荡器 - 内置 48MHz RC 振荡器 - 内置 32kHz RC 振荡器 - 内置 10kHz RC 振荡器 - 内置 150kHz RC 振荡器 - 时钟监测系统 - 允许独立关断各外设时钟 - 支持最多 55 路 I/O 接口 - 所有 I/O 口支持中断功能 - 所有 I/O 支持中断输入滤波功能 - 四通道 DMA 控制器 - 模数转换器 - 12 位精度,±1 LSB - 最高 1M SPS 转换速度   - 内置电压参考   - 模拟看门狗功能   - 内置温度传感器 - 双路电压比较器 - 实时时钟和日历 - 支持由 Sleep/DeepSleep 模式唤醒 - 定时器 - 16 位高级控制定时器,支持 6 路捕获 / 比较通道和 3 对互补 PWM 输出,死区时间和灵活的同步功能   - 三组 16 位通用定时器   - 三组 16 位基本定时器   - 一组 16 位超低功耗定时器   - 16 位时钟校准定时器   -  窗口看门狗定时器   - 独立看门狗定时器 - 通信接口 - 三路低功耗 UART,支持小数波特率,支持 LIN 通信接口,单总线实现 ISO7816 - 两路 SPI 接口 12Mbit/s - 两路 I2C 接口 1Mbit/s - IR 调制器 - 4×40、6×38 或 8×36 LCD 段码液晶驱动器 - ​        串行调试接口 (SWD) - 80 位唯一 ID ## 概述 - CW32L052 是基于 eFlash 的单芯片低功耗微控制器,集成了主频高达 48MHz 的 ARM® Cortex®-M0+ 内核、 高速嵌入式存储器(多至 64K 字节 FLASH 和多至 8K 字节 SRAM) - 全面的增强型外设和 I/O 口。 - 三路 UART、两路 SPI 和两路 I2C)、12 位高速 ADC、六组通用和基本定时器、 一组低功耗定时器以及一组高级控制 PWM 定时器。 - CW32L052 可以在 -40° C 到 85° C 的温度范围内工作 - 供电电压宽达 1.65V ~ 5.5V。 - 支持 Sleep 和 DeepSleep 两种低功耗工作模式 ## 内部框架图 ## 芯片外设明细说明 ## 低功耗工作模式 CW32L052 微控制器支持两种低功耗模式。 - Sleep 模式 在 Sleep 模式下,CPU 停止运行,**所有外设保持工作**,并且可以在发生中断或事件的时候唤醒 CPU。 - DeepSleep 模式 DeepSleep 用于实现最低功耗,CPU 停止运行,高速时钟模块(HSE、HSIOSC)自动关闭,**低速时钟(LSE、 LSI、RC10K、RC150K)保持原状态不变**。 当发生外部复位,或 IWDT 复位,或部分外设中断发生,或 RTC 事件发生时,芯片退出 DeepSleep 模式 ## 低功耗定时器(LPTIM) 内部集成 1 个 16 位低功耗定时器(LPTIM),可以以很低的功耗**实现定时或对外部脉冲计数的功能**。通过选 择合适的时钟源和触发信号,可以实现系统低功耗休眠时将其唤醒的功能。LPTIM 内部具有**一个**比较寄存器, 可实现比较输出和 PWM 输出,并可以控制输出波形的极性。此外,LPTIM 还可以与正交编码器连接,自动 实现递增计数和递减计数 ## 红外调制发送器(IR) 内置红外调制发送器 (IR),**通过两路通用定时器或一路通用定时器与 UART 配合使用**,可方便实现各种标准 的 PWM 或 PPM 编码方式,也可实现 UART 数据的红外调制发送。 红外调制发送器(IR)的主要特性有: - 支持 IrDA 标准 1.0 的 SIR - 最高数据速率 115.2kbps - 可适应高低电平红外发射管 ## CW32L052 的时钟树 ## 引脚分布 ## 引脚定义 ### 1-15 ### 16-28 ### 29-42 ### 43-55 ### 56-64 # 引脚复用 GPIOA ### GPIOB ### GPIOC ### GPIOD GPIOF

  • 2023-07-07
  • 发表了主题帖: 【极海APM32F4xx Tiny】学习笔记09-串口DMA接收数据

    # 【极海APM32F4xx Tiny】学习笔记09-串口DMA接收数据 1. 一共有两个 DMA 控制器,共 16 个数据流。每个数据流对应 8 个通道,但每 个数据流同一时刻只能使用 1 个通道。每个数据流可设置优先级,仲裁器可根据 数据流的优先级协调各个数据流对应的 DMA 请求的优先级 2. 每个数据流都有 5 个事件标志和独立中断 3. 第一阶段软件阶段分为最高、高、中等和低四个优先级;第二阶段硬件 阶段,在软件优先级相同的情况下,数据流编号越低优先级越高 4. FIFO 用来在源数据传输到目标地址之前临时存放数据,每个数据流都有 1 个独 立的 4 字 FIFO,可通过软件来控制 FIFO 阈值为 1/4、1/2、3/4 或满 这里由表格得到串口1的接收dma是**dma2的数据流2的通道4**,或者是**dma2的数据流5的通道4** ## 自己的实例函数 ### 头文件 ```c #ifndef __BSP_USART_IT_H #include "bsp_delay.h" #include "apm32f4xx.h" #include "apm32f4xx_gpio.h" #include "apm32f4xx_eint.h" #include "apm32f4xx_rcm.h" #include "apm32f4xx_syscfg.h" #include "apm32f4xx_misc.h" #include "apm32f4xx_usart.h" #define RX_BUFF_SIZE 256 typedef enum {         UART_1,         UART_2,         UART_NUM                 }em_uart_id; void bsp_uart_send_data(em_uart_id id,uint8_t *dat, uint32_t count); void bsp_uart_it_init_all(void); void bsp_uart_recv_data(em_uart_id id,uint8_t *dat, uint32_t *count); void bsp_uart_dma_send_data(em_uart_id id, uint8_t *buff,uint32_t len); #endif ``` ### 源文件 ```c /* Includes */ #include "../usart_it/bsp_uart_it.h" #include #include "apm32f4xx_dma.h" #define min(num0,num1) (num0>num1?num1:num0) typedef struct {     DMA_T *dma;//哪一个dma外设     DMA_Stream_T *dma_stream; //dma数据流     DMA_CHANNEL_T ch;//dma通道     IRQn_Type irq;//dma对应的通道 } dma_t; static dma_t dmas[UART_NUM]= {     {  DMA2,DMA2_Stream5,DMA_CHANNEL_4, DMA2_STR5_IRQn}, }; typedef struct {     GPIO_T *tx_gpio_grp;     GPIO_PIN_T tx_pin;     uint32_t tx_rcc;     GPIO_PIN_SOURCE_T tx_pin_source;     GPIO_T *rx_gpio_grp;     GPIO_PIN_T rx_pin;     uint32_t rx_rcc;     GPIO_PIN_SOURCE_T rx_pin_source;     GPIO_AF_T gpio_af;     USART_T *uart;     IRQn_Type irq;     uint32_t uart_rcc;     dma_t *pdma;         //        dma_t *pdma_tx;     uint8_t rx_buff[RX_BUFF_SIZE];     uint8_t tx_buff[RX_BUFF_SIZE];     uint16_t rx_count;     uint16_t idle; } uart_it_t; #define DATA_BUF_SIZE       (32) static uart_it_t uarts_it[UART_NUM]= {     {   GPIOA,GPIO_PIN_9,RCM_AHB1_PERIPH_GPIOA,GPIO_PIN_SOURCE_9,         GPIOA,GPIO_PIN_10,RCM_AHB1_PERIPH_GPIOA,GPIO_PIN_SOURCE_10,GPIO_AF_USART1,         USART1,USART1_IRQn,RCM_APB2_PERIPH_USART1,dmas+0,     },     {   GPIOA,GPIO_PIN_2,RCM_AHB1_PERIPH_GPIOA,GPIO_PIN_SOURCE_2,         GPIOA,GPIO_PIN_3,RCM_AHB1_PERIPH_GPIOA,GPIO_PIN_SOURCE_3,GPIO_AF_USART2,         USART2,USART2_IRQn,RCM_APB1_PERIPH_USART2,0,     }, }; static void bsp_uart_dma_config(uart_it_t *puart, dma_t* pdma) {     /* Configure USART DMA*/     //  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);     if(pdma->dma==DMA2)     {         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);     }     else     {         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA1);     }     DMA_Config_T dmaConfigStruct;     dmaConfigStruct.bufferSize          = DATA_BUF_SIZE;     dmaConfigStruct.fifoMode            = DMA_FIFOMODE_DISABLE;     dmaConfigStruct.fifoThreshold       = DMA_FIFOTHRESHOLD_QUARTER;     dmaConfigStruct.memoryBurst         = DMA_MEMORYBURST_SINGLE;     dmaConfigStruct.memoryDataSize      = DMA_MEMORY_DATA_SIZE_BYTE;     dmaConfigStruct.memoryInc           = DMA_MEMORY_INC_ENABLE;     dmaConfigStruct.loopMode            = DMA_MODE_CIRCULAR;     dmaConfigStruct.peripheralBaseAddr  =(uint32_t) &(puart->uart->DATA) ;         //(uint32_t) (&(USART1->DATA));     dmaConfigStruct.peripheralBurst     = DMA_PERIPHERALBURST_SINGLE;     dmaConfigStruct.peripheralDataSize  = DMA_PERIPHERAL_DATA_SIZE_BYTE;     dmaConfigStruct.peripheralInc       = DMA_PERIPHERAL_INC_DISABLE;     dmaConfigStruct.priority            = DMA_PRIORITY_HIGH; //    /* 串口发送dma DMA*/ //    dmaConfigStruct.channel             = DMA_CHANNEL_4; //    dmaConfigStruct.dir                 = DMA_DIR_MEMORYTOPERIPHERAL; //    dmaConfigStruct.memoryBaseAddr      = (uint32_t)tx_buff; //    DMA_Config(DMA2_Stream7, &dmaConfigStruct);     /* USART RX DMA*/     dmaConfigStruct.channel             = pdma->ch;// DMA_CHANNEL_4;     dmaConfigStruct.dir                 = DMA_DIR_PERIPHERALTOMEMORY;     dmaConfigStruct.memoryBaseAddr      = (uint32_t)puart->rx_buff;     DMA_Config(pdma->dma_stream, &dmaConfigStruct);// DMA_Config(DMA2_Stream5, &dmaConfigStruct);     DMA_Enable(pdma->dma_stream);     USART_EnableDMA(puart->uart,USART_DMA_RX);     DMA_EnableInterrupt(pdma->dma_stream,DMA_INT_TCIFLG);     NVIC_EnableIRQRequest(pdma->irq,1,0);//DMA2_STR5_IRQn } static void bsp_uart_dma_send_config(uart_it_t *puart, dma_t* pdma) {     /* Configure USART DMA*/     //  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);     if(pdma->dma==DMA2)     {         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);     }     else     {         RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA1);     }     DMA_Config_T dmaConfigStruct;     dmaConfigStruct.bufferSize          = DATA_BUF_SIZE;     dmaConfigStruct.fifoMode            = DMA_FIFOMODE_DISABLE;     dmaConfigStruct.fifoThreshold       = DMA_FIFOTHRESHOLD_QUARTER;     dmaConfigStruct.memoryBurst         = DMA_MEMORYBURST_SINGLE;     dmaConfigStruct.memoryDataSize      = DMA_MEMORY_DATA_SIZE_BYTE;     dmaConfigStruct.memoryInc           = DMA_MEMORY_INC_ENABLE;     dmaConfigStruct.loopMode            = DMA_MODE_NORMAL;//这里使用普通方式     dmaConfigStruct.peripheralBaseAddr  =(uint32_t) &(puart->uart->DATA) ;     dmaConfigStruct.peripheralBurst     = DMA_PERIPHERALBURST_SINGLE;     dmaConfigStruct.peripheralDataSize  = DMA_PERIPHERAL_DATA_SIZE_BYTE;     dmaConfigStruct.peripheralInc       = DMA_PERIPHERAL_INC_DISABLE;     dmaConfigStruct.priority            = DMA_PRIORITY_HIGH;     /* 串口发送dma DMA*/     dmaConfigStruct.channel             = pdma->ch;     dmaConfigStruct.dir                 = DMA_DIR_MEMORYTOPERIPHERAL;//这里传输方向不一样     dmaConfigStruct.memoryBaseAddr      = (uint32_t)puart->tx_buff;     DMA_Config(DMA2_Stream7, &dmaConfigStruct);     USART_EnableDMA(puart->uart,USART_DMA_TX);//这里是发送 //                这里的中断可以不开启 //    DMA_EnableInterrupt(pdma->dma_stream,DMA_INT_TCIFLG); //    NVIC_EnableIRQRequest(pdma->irq,1,0);// } /*         dma数据发送 */ void bsp_uart_dma_send_data(em_uart_id id, uint8_t *buff,uint32_t len) {     uart_it_t *puart;     if(UART_NUM>id)     {   puart = uarts_it+id;         memcpy(puart->tx_buff,buff,min(len,DATA_BUF_SIZE));         DMA_ConfigDataNumber(puart->pdma->dma_stream,min(len,DATA_BUF_SIZE));         DMA_Enable(puart->pdma->dma_stream);     } } static void bsp_uart_it_config(uart_it_t *puart) {     USART_Config_T usartConfigStruct;     usartConfigStruct.baudRate = 115200;     usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;     usartConfigStruct.mode = USART_MODE_TX_RX;     usartConfigStruct.parity = USART_PARITY_NONE;     usartConfigStruct.stopBits = USART_STOP_BIT_1;     usartConfigStruct.wordLength = USART_WORD_LEN_8B;     if (puart->uart == USART1 || puart->uart == USART6)     {         RCM_EnableAPB2PeriphClock(puart->uart_rcc);     }     else     {         RCM_EnableAPB1PeriphClock(puart->uart_rcc);     }     /** USART configuration */     USART_Config(puart->uart, &usartConfigStruct);     /** 使能串口的接收和空闲中断 */     if(!puart->pdma)     {         USART_EnableInterrupt(puart->uart, USART_INT_RXBNE);     }     USART_EnableInterrupt(puart->uart,USART_INT_IDLE);     USART_ClearStatusFlag(puart->uart, USART_FLAG_RXBNE);     NVIC_EnableIRQRequest(puart->irq,1,0);     if(puart->pdma)     {         bsp_uart_dma_config(puart,puart->pdma);     }     /** Enable USART */     USART_Enable(puart->uart); } void DMA2_STR5_IRQHandler() {     volatile int len=0;     if(DMA_ReadIntFlag(DMA2_Stream5,DMA_INT_TCIFLG5))     {         DMA_ClearIntFlag(DMA2_Stream5,DMA_INT_TCIFLG5);         len = DMA_ReadDataNumber (DMA2_Stream5);     } } static void bsp_uart_it_gpio_config(uart_it_t *puart) {     GPIO_Config_T GPIO_configStruct;     GPIO_ConfigStructInit(&GPIO_configStruct);     /** 使能gpio的rcc*/     RCM_EnableAHB1PeriphClock(puart->tx_rcc|puart->rx_rcc );     /** Connect PXx to USARTx_Tx */     GPIO_ConfigPinAF(puart->tx_gpio_grp, puart->tx_pin_source, puart->gpio_af);     /** Connect PXx to USARTx_Rx */     GPIO_ConfigPinAF(puart->rx_gpio_grp, puart->rx_pin_source, puart->gpio_af);     /** Configure USART Tx as alternate function push-pull */     GPIO_configStruct.mode = GPIO_MODE_AF;     GPIO_configStruct.pin = puart->tx_pin;     GPIO_configStruct.speed = GPIO_SPEED_50MHz;     GPIO_Config(puart->tx_gpio_grp, &GPIO_configStruct);     /** Configure USART Rx as input floating */     GPIO_configStruct.mode = GPIO_MODE_AF;     GPIO_configStruct.pin = puart->rx_pin;     GPIO_Config(puart->rx_gpio_grp, &GPIO_configStruct); } void bsp_uart_it_init_all(void) {     for(int i=0; iid)         puart = uarts_it+id;     while(puart && count--)     {         while(USART_ReadStatusFlag(puart->uart, USART_FLAG_TXBE) == RESET);         USART_TxData(puart->uart, *dat++);     } } void bsp_uart_recv_data(em_uart_id id,uint8_t *dat, uint32_t *count) {     uart_it_t *puart;     if(UART_NUM>id)         puart = uarts_it+id;     if(puart && dat&&count && puart->idle)     {         *count = min(puart->rx_count,*count);         memcpy(dat, puart->rx_buff,*count);         puart->rx_count=0;     }     else {         *count=0;     } } static void  bsp_uart_ira_handler(uart_it_t *puart) {     if(USART_ReadIntFlag(puart->uart, USART_INT_RXBNE) == SET)     {         USART_ClearIntFlag(puart->uart, USART_INT_RXBNE);         puart->rx_buff[puart->rx_count++%RX_BUFF_SIZE] = (uint8_t)USART_RxData(puart->uart);     }     else if (USART_ReadIntFlag(puart->uart, USART_INT_IDLE) == SET)     {         USART_ClearIntFlag(puart->uart, USART_INT_IDLE);         puart->idle=1;         USART_RxData(puart->uart);         if(puart->pdma)         {             dma_t *pdma = puart->pdma;             puart->rx_count = DATA_BUF_SIZE-DMA_ReadDataNumber (pdma->dma_stream);             DMA_Disable(pdma->dma_stream);             DMA_ConfigDataNumber(pdma->dma_stream,DATA_BUF_SIZE);             DMA_Enable(pdma->dma_stream);         }     } } void USART1_IRQHandler(void) {     bsp_uart_ira_handler(uarts_it+UART_1); } void USART2_IRQHandler(void) {     //  bsp_uart_ira_handler(uarts_it+UART_2); } ``` ### 使用 ```c /* Includes */ #include "main.h" #include #include "bsp_led.h" #include "bsp_usart.h" #include "../key/bsp_button_instance.h" #include "../usart_it/bsp_uart_it.h"   #include "dma/dma.h" /* Delay */ void Delay(uint32_t count); /*! * @brief     Main program * * @param     None * * @retval    None */ int main(void) {     led_init(LED0);     led_init(LED1);                 bsp_uart_it_init_all();                 printf("hello apm32\r\n");                                         init_key_btn();                 uint8_t buff[256];                 uint32_t len =256;     while (1)     {         Delay(0x2FFFFF);         led_toggle(LED0);         led_toggle(LED1);                                 key_lib_buttons_process();                                 len=256;                                 bsp_uart_recv_data(UART_1,buff,&len);                                                                         if(len)                                 {                                                 for(int i=0;i

  • 回复了主题帖: 测评入围名单: 武汉芯源CW32L052R8T6 StartKit 评估板

    客人信息无误,可以发货。

  • 发表了主题帖: 极海APM32F4xx Tiny】学习笔记08-RTT 链表使用方法

    极海APM32F4xx Tiny】学习笔记08-RTT 链表使用方法 # 1.双向链表基本结构 ```c #define rt_inline                   static __inline /** * 双向链表 */ struct rt_list_node {     struct rt_list_node *next;                          /**< point to next node. */     struct rt_list_node *prev;                          /**< point to prev node. */ }; typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */ ``` # 2.节点初始化--2个方法 ```c /** * @brief initialize a list object 初始化链表,使nex= pre = 自己 */ #define RT_LIST_OBJECT_INIT(object) { &(object), &(object) } ``` ```c /** * @brief initialize a list * * @param l list to be initialized 初始化链表,使nex= pre = 自己 */ rt_inline  void rt_list_init(rt_list_t *l) {     l->next = l->prev = l; } ``` # 3.在某一个节点后边插入一个节点 ```c /** * @brief insert a node after a list * * @param l list to insert it * @param n new node to be inserted 向链表某一个节点后边插入一个节点 */ rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) {     l->next->prev = n;     n->next = l->next;     l->next = n;     n->prev = l; } ``` # 4.在某一个节点前边插入一个节点 ```c /** * @brief insert a node before a list * * @param n new node to be inserted * @param l list to insert it 在某一个节点之前插入一个节点 */ rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n) {     l->prev->next = n;     n->prev = l->prev;     l->prev = n;     n->next = l; } ``` # 5.移除一个节点 ```c /** * @brief remove node from list. * @param n the node to remove from the list. 移除一个节点 */ rt_inline void rt_list_remove(rt_list_t *n) {     n->next->prev = n->prev;     n->prev->next = n->next;     n->next = n->prev = n; } ``` # 6.判定链表是不是空 就是判定是不是自己指向自己 ```c /** * @brief tests whether a list is empty * @param l the list to test. 判定链表是不是空链表,就是判定是不是自己指向自己 */ rt_inline int rt_list_isempty(const rt_list_t *l) {     return l->next == l; } ``` # 7.获取链表长度 ```c /** * @brief get the list length * @param l the list to get. 获取链表长度 */ rt_inline unsigned int rt_list_len(const rt_list_t *l) {     unsigned int len = 0;     const rt_list_t *p = l;     while (p->next != l)     {         p = p->next;         len ++;     }     return len; } ``` 已知结构体内部一个成员的地址**can_dev**,根据机构体类型**struct ra_can**和成员名字**can_dev** 得到结构体实例对象**can**的地址 # 8.获取结构体的入口地址 ```c /** * @brief 获取结构体的入口地址get the struct for this entry * @param 结构体中一个成员的入口地址 node the entry point * @param 结构体的名字 type the type of structure * @param 结构体内部成员的名字 member the name of list in structure         已知成员的地址,获取机构体的头部 */ #define rt_list_entry(node, type, member) \     rt_container_of(node, type, member) ``` # 9.遍历整个链表 ```c /** * rt_list_for_each - iterate over a list * @param pos the rt_list_t * 传入一个链表指针,用于返回每个成员的指针 * @param 传入链表的头指针 head the head for your list. 链表遍历 */ #define rt_list_for_each(pos, head) \     for (pos = (head)->next; pos != (head); pos = pos->next) ``` # 10.已知成员的地址遍历整个链表 ```c /** * rt_list_for_each_entry  -   iterate over list of given type * @param pos 结构体类型的指针,用于返回结构体的入口地址 the type * to use as a loop cursor. * @param head 链表头指针 the head for your list. * @param 接头体成语名称 member the name of the list_struct within the struct. */ #define rt_list_for_each_entry(pos, head, member) \     for (pos = rt_list_entry((head)->next, typeof(*pos), member); \          &pos->member != (head); \          pos = rt_list_entry(pos->member.next, typeof(*pos), member)) ``` # 我移植注释过的链表 ```c #ifndef __RTT_LIST_H__ #define __RTT_LIST_H__ #define rt_inline /** * Double List structure */ struct rt_list_node {     struct rt_list_node *next;                          /**< point to next node. */     struct rt_list_node *prev;                          /**< point to prev node. */ }; typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */ /** * @addtogroup KernelService */ /**@{*/ /** * rt_container_of - return the start address of struct type, while ptr is the * member of struct type. 给定一个结构体成员地址,返回结构体的首地址 */ #define rt_container_of(ptr, type, member) \     ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) /** * @brief initialize a list object 初始化链表,使nex= pre = 自己 */ #define RT_LIST_OBJECT_INIT(object) { &(object), &(object) } /** * @brief initialize a list * * @param l list to be initialized 初始化链表,使nex= pre = 自己 */ rt_inline void rt_list_init(rt_list_t *l) {     l->next = l->prev = l; } /** * @brief insert a node after a list * * @param l list to insert it * @param n new node to be inserted 向链表某一个节点后边插入一个节点 */ rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) {     l->next->prev = n;     n->next = l->next;     l->next = n;     n->prev = l; } /** * @brief insert a node before a list * * @param n new node to be inserted * @param l list to insert it 在某一个节点之前插入一个节点 */ rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n) {     l->prev->next = n;     n->prev = l->prev;     l->prev = n;     n->next = l; } /** * @brief remove node from list. * @param n the node to remove from the list. 移除一个节点 */ rt_inline void rt_list_remove(rt_list_t *n) {     n->next->prev = n->prev;     n->prev->next = n->next;     n->next = n->prev = n; } /** * @brief tests whether a list is empty * @param l the list to test. 判定链表是不是控制,就是判定是不是自己指向自己 */ rt_inline int rt_list_isempty(const rt_list_t *l) {     return l->next == l; } /** * @brief get the list length * @param l the list to get. 获取链表长度 */ rt_inline unsigned int rt_list_len(const rt_list_t *l) {     unsigned int len = 0;     const rt_list_t *p = l;     while (p->next != l)     {         p = p->next;         len ++;     }     return len; } /** * @brief 获取结构体的入口地址get the struct for this entry * @param 结构体中一个成员的入口地址 node the entry point * @param 结构体的名字 type the type of structure * @param 结构体内部成员的名字 member the name of list in structure         已知成员的地址,获取机构体的头部 */ #define rt_list_entry(node, type, member) \     rt_container_of(node, type, member) /** * rt_list_for_each - iterate over a list * @param pos the rt_list_t * to use as a loop cursor. * @param head the head for your list. 链表遍历 */ #define rt_list_for_each(pos, head) \     for (pos = (head)->next; pos != (head); pos = pos->next) /** * rt_list_for_each_safe - iterate over a list safe against removal of list entry * @param pos the rt_list_t * to use as a loop cursor. * @param n another rt_list_t * to use as temporary storage * @param head the head for your list. */ #define rt_list_for_each_safe(pos, n, head) \     for (pos = (head)->next, n = pos->next; pos != (head); \         pos = n, n = pos->next) /** * rt_list_for_each_entry  -   iterate over list of given type * @param pos 结构体类型的指针,用于返回结构体的入口地址 the type * to use as a loop cursor. * @param head 链表头指针 the head for your list. * @param 接头体成语名称 member the name of the list_struct within the struct. */ #define rt_list_for_each_entry(pos, head, member) \     for (pos = rt_list_entry((head)->next, typeof(*pos), member); \          &pos->member != (head); \          pos = rt_list_entry(pos->member.next, typeof(*pos), member)) /** * rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_struct within the struct. */ #define rt_list_for_each_entry_safe(pos, n, head, member) \     for (pos = rt_list_entry((head)->next, typeof(*pos), member), \          n = rt_list_entry(pos->member.next, typeof(*pos), member); \          &pos->member != (head); \          pos = n, n = rt_list_entry(n->member.next, typeof(*n), member)) /** * rt_list_first_entry - get the first element from a list * @param ptr the list head to take the element from. * @param type the type of the struct this is embedded in. * @param member the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define rt_list_first_entry(ptr, type, member) \     rt_list_entry((ptr)->next, type, member) #endif ``` # rtt_list 链表使用实例 ```c #include "stdio.h" #include #include "rtt_list.h" //定义一个数据结构 typedef struct {         rt_list_t next;         uint8_t id;         uint8_t dir;         uint8_t speed; }data_t; //定义一些数据 data_t car_data = { { 0,0 },1 }; data_t car_data2 = { { 0,0 },2 }; data_t car_data3 = { { 0,0 },3 }; data_t car_data4 = { { 0,0 },4 }; rt_list_t head; void list_user_example(void) {         //初始化链表         rt_list_init(&head);         //在car_data 之后插入一个节点         rt_list_insert_after(&head, &car_data.next);         //在car_data 之后插入一个节点         rt_list_insert_after(&car_data.next, &car_data2.next);         //在car_data3之前插入一个节点         rt_list_insert_before(&car_data2.next, &car_data3.next);         //遍历每一个节点         rt_list_t *pos;         rt_list_for_each(pos, &head)         {                 //获取数据结构对象的地址                 data_t *pdata = rt_list_entry(pos, data_t, next);                 printf("%d\r\n", pdata->id);         } } int main() {         list_user_example();         return 1; }         ``` #rtt_list.h ```c #ifndef __RTT_LIST_H__ #define __RTT_LIST_H__ #define rt_inline /** * Double List structure */ struct rt_list_node {     struct rt_list_node *next;                          /**< point to next node. */     struct rt_list_node *prev;                          /**< point to prev node. */ }; typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */ /** * @addtogroup KernelService */ /**@{*/ /** * rt_container_of - return the start address of struct type, while ptr is the * member of struct type. 给定一个结构体成员地址,返回结构体的首地址 */ #define rt_container_of(ptr, type, member) \     ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) /** * @brief initialize a list object 初始化链表,使nex= pre = 自己 */ #define RT_LIST_OBJECT_INIT(object) { &(object), &(object) } /** * @brief initialize a list * * @param l list to be initialized 初始化链表,使nex= pre = 自己 */ rt_inline void rt_list_init(rt_list_t *l) {     l->next = l->prev = l; } /** * @brief insert a node after a list * * @param l list to insert it * @param n new node to be inserted 向链表某一个节点后边插入一个节点 */ rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) {     l->next->prev = n;     n->next = l->next;     l->next = n;     n->prev = l; } /** * @brief insert a node before a list * * @param n new node to be inserted * @param l list to insert it 在某一个节点之前插入一个节点 */ rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n) {     l->prev->next = n;     n->prev = l->prev;     l->prev = n;     n->next = l; } /** * @brief remove node from list. * @param n the node to remove from the list. 移除一个节点 */ rt_inline void rt_list_remove(rt_list_t *n) {     n->next->prev = n->prev;     n->prev->next = n->next;     n->next = n->prev = n; } /** * @brief tests whether a list is empty * @param l the list to test. 判定链表是不是控制,就是判定是不是自己指向自己 */ rt_inline int rt_list_isempty(const rt_list_t *l) {     return l->next == l; } /** * @brief get the list length * @param l the list to get. 获取链表长度 */ rt_inline unsigned int rt_list_len(const rt_list_t *l) {     unsigned int len = 0;     const rt_list_t *p = l;     while (p->next != l)     {         p = p->next;         len ++;     }     return len; } /** * @brief 获取结构体的入口地址get the struct for this entry * @param 结构体中一个成员的入口地址 node the entry point * @param 结构体的名字 type the type of structure * @param 结构体内部成员的名字 member the name of list in structure         已知成员的地址,获取机构体的头部 */ #define rt_list_entry(node, type, member) \     rt_container_of(node, type, member) /** * rt_list_for_each - iterate over a list * @param pos the rt_list_t * to use as a loop cursor. * @param head the head for your list. 链表遍历 */ #define rt_list_for_each(pos, head) \     for (pos = (head)->next; pos != (head); pos = pos->next) /** * rt_list_for_each_safe - iterate over a list safe against removal of list entry * @param pos the rt_list_t * to use as a loop cursor. * @param n another rt_list_t * to use as temporary storage * @param head the head for your list. */ #define rt_list_for_each_safe(pos, n, head) \     for (pos = (head)->next, n = pos->next; pos != (head); \         pos = n, n = pos->next) /** * rt_list_for_each_entry  -   iterate over list of given type * @param pos 结构体类型的指针,用于返回结构体的入口地址 the type * to use as a loop cursor. * @param head 链表头指针 the head for your list. * @param 接头体成语名称 member the name of the list_struct within the struct. */ #define rt_list_for_each_entry(pos, head, member) \     for (pos = rt_list_entry((head)->next, typeof(*pos), member); \          &pos->member != (head); \          pos = rt_list_entry(pos->member.next, typeof(*pos), member)) /** * rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @param pos the type * to use as a loop cursor. * @param n another type * to use as temporary storage * @param head the head for your list. * @param member the name of the list_struct within the struct. */ #define rt_list_for_each_entry_safe(pos, n, head, member) \     for (pos = rt_list_entry((head)->next, typeof(*pos), member), \          n = rt_list_entry(pos->member.next, typeof(*pos), member); \          &pos->member != (head); \          pos = n, n = rt_list_entry(n->member.next, typeof(*n), member)) /** * rt_list_first_entry - get the first element from a list * @param ptr the list head to take the element from. * @param type the type of the struct this is embedded in. * @param member the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define rt_list_first_entry(ptr, type, member) \     rt_list_entry((ptr)->next, type, member) #endif ```

最近访客

< 1/2 >

统计信息

已有35人来访过

  • 芯积分:125
  • 好友:--
  • 主题:19
  • 回复:13
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言