chejia12

  • 2024-05-28
  • 回复了主题帖: 选KiCAD还是国产立创EDA求建议

    立创的可以啊,我一直都用他

  • 2024-03-20
  • 回复了主题帖: 国产芯榜:网友新推荐,几毛钱的普冉PY32F002A和沁恒ch32v003,欢迎跟帖讨论

    概述 CH32V003 系列是基于青稞 RISC-V2A 内核设计的工业级通用微控制器,在产品功能上支持 48MHz 系统主频。该系列具有宽压、单线调试、低功耗、超小封装等特点。提供常用的外设功能,内置 1 组 DMA控制器、1 组 10 位模数转换 ADC、1 组运放比较器、多组定时器、标准通讯接口如 USART、I2C、SPI 等。产品额定工作电压为 3.3V 或 5V,工作温度范围为-40℃~85℃工业级。产品特性l 内核 Core:- 青稞 32 位 RISC-V 内核,RV32EC 指令集- 快速可编程中断控制器+硬件中断堆栈- 支持 2 级中断嵌套- 支持系统主频 48MHz l 存储器: - 2KB 易失数据存储区 SRAM - 16KB 程序存储区 CodeFlash - 1920B 系统引导程序存储区 BootLoader - 64B 系统非易失配置信息存储区- 64B 用户自定义信息存储区l 电源管理和低功耗: - 系统供电 VDD额定:3.3V 或 5V - 低功耗模式:睡眠、待机l 系统时钟、复位- 内嵌出厂调校的 24MHz 的 RC 振荡器- 内嵌 128kHz 的 RC 振荡器- 外部支持 4~25MHz 高速振荡器- 上/下电复位、可编程电压监测器l 1 组 1 路通用 DMA 控制器 - 7 个通道,支持环形缓冲区管理- 支持 TIMx/ADC/USART/I2C/SPI l 1 组运放、比较器:连接 ADC 和 TIM2 l 1 组 10 位模数转换 ADC- 模拟输入范围:0~VDD - 8 路外部信号+2 路内部信号通道 - 支持外部延迟触发l 多组定时器- 1 个 16 位高级定时器,增加死区控制和紧急刹车,提供用于电机控制的 PWM 互补输出- 1 个 16 位通用定时器,提供输入捕获/输出比较/PWM/脉冲计数及增量编码器输入- 2 个看门狗定时器(独立和窗口型)- 系统时基定时器:32 位计数器l 标准通讯接口:- 1 个 USART 接口- 1 个 I2C 接口- 1 个 SPI 接口l GPIO 端口:- 3 组 GPIO 端口,18 个 I/O 口- 映像 1 个外部中断l 安全特性:64 位芯片唯一 ID l 调试模式:串行单线调试接口 l 封装形式:SOP、TSSOP、QFN

  • 2023-12-17
  • 发表了主题帖: 先楫半导体HPM5361EVK--pwm

    本帖最后由 chejia12 于 2023-12-17 21:35 编辑 # pwm控制器 这里需要特别注意寄存器的影子寄存器的生效时机,我当初就是看不懂 ```c //配置选择影子寄存器生效时机         //pwm_load_cmp_shadow_on_match ( PWM, cmp_index + 2, &cmp_config[1] );         ``` 1.支持2个pwm定时器,每个pwm支持28位计数器,支持24个通道 **信号连接如下**: 1. 通道0-7输出pwm,连接到IO上 2. 通道8-23输出**连接到电机控制单元的互联管理器** 3. 输入捕获通道0-7来自IO 4. 输入捕获的8-23**来自电机控制单元的互联管理器** 5. 同步输入**来自电机控制单元的互联管理器** 6. 强制输出的使能输入**来自电机控制单元的互联管理器** 7. 强制输出的影子寄存器的生效触发 **来自电机控制单元的互联管理器** 8. 外部故障来自IO 9. 内部故障输入**来自电机控制单元的互联管理器**** ## 主要特性 - **28 (24 +4) 位**分辨率计数器,支持**向上**计数模式 - 支持计数器**同步** - 多达 24 个比较器,支持用作**输出比较,或者输入捕获** - 多达 24 个通道,其中通道 0∼7 可用于 PWM 输出   - 支持 **8 路独立**或者 4 **对互补** PWM 输出   - 互补 PWM 支持**死区插入**,支持独立配置**双侧**死区宽度   - 支持把 PWM 输出**强制设置为指定状**态   - 支持故障保护输入,在出错时(如故障保护输入时),**单独配置每个 PWM 输出通道的状态** - 支持为每个输出通道**灵活地分配数目不等的比较器**,灵活控制输出信号,生成例如边沿对齐 PWM、左右不对称的中央对齐 PWM 以及更复杂的输出信号 - 支持生成各类 DMA 请求和中断请求 - 部分寄存器配有影子寄存器,支持灵活的寄存器新值**更新/生效时机** ## **器时间基准** **时间基准模块的作用是决定 PWM 定时器运行的时间和周期** - **计数器**,计数器包括**计数器和扩展计数**两部分,计数器 24 位,扩展 4 位。可以合并成 28 位计数器使用 - **起始寄存器**,可以设置计数器起始值和扩展起始值 - **重载寄存器**,可以设置计数器重载值和扩展重载值 计数器使能 (GCR[CEN] 位置 1) 以后,总是从起始值开始计数,当计时器的值(CNT)计数至重载值(RLD)后,重载标志**RLDF**位置 1,此时,扩展计数器值 +1,计数器的值恢复到起始值(STA)。当扩展计数器值(XCNT)也计数到扩展重载值(**XRLD**)后,重载标志XRLDF位置 1,扩展计数器恢复到起始值 ### 同步 1. 需要打开 2. 同步触发输入可以**重置计数器到起始值** **半重载标志位HALFRLDF** ## **PWM** **生成** 1. PWM 生成需要**配合使用比较器和通道,主要功能是以通道为单位,利用比较器组合生成输出参考信号** 2. PWM 生成模块包括 24 个比较器和 24 个输出通道 3. 中通道 0 到通道 7 是 PWM 输出通道,通道输出 CH0REF ∼ CH7REF **连接到 PWM 控制逻辑**,如互补控制,死区生成,故障保护等模块。最终输出信号 OUT0∼OUT7 到芯片的管脚上 4. 通道 8 及之后的通道是通用输出通道,这些通道的输出参考信号**不经过 PWM 控制逻辑**,也可以输出信号供内外部使用 5. PWM 定时器的 24 个比较器,当它们用于 PWM 生成时,**需要配置为输出比较模式** 6. 比较器寄存器还包含 **4 位为小数比较位** 7. 用户可以把一个或者多个连续的比较器分配给某个通道,实现灵活复杂的输出,用户通过设置 CHCFGx [CMPSELBEG] 位,选择分配给通道 x 的比较寄存器**起始序号**。通过设置 CHCFGx [CMPSELEND] 位,选择分配给通道 x的比较寄存器**末尾序号**。 8. 当计数器 CNT 计数达到比较器 CMPx 配置的CMP或者XCMP时,产生**匹配事件,此时 OCx 输出置逻辑 1**。当计数器 CNT 值到**达重载寄存器,发生重载事件,输出重置逻辑 0** 9. 通道 x 的输出参考信号 CHxREF,由分配给它的全部比较器输出 OC*BEG* ∼OC*END* **异或后得到**。 10. CMPHLF是**半周期比较位**,由 PWM 定时器时钟的下边沿实现,该位置 1,可以使**匹配事件的生成时间延后 1/2 时钟周期**。 11. CMPJIT是**抖动比较位**,由 4,8,16 个周期边沿抖动,平均后**实现精度达 1/4,1/8 和 1/16 时钟周期的延时效果**。 12. 13. ### **PWM** **输出控制概述** PWM 输出通道(通道 0∼7)的参考信号(CH0REF∼CH7REF)经过后续的互补控制,死区插入,取反控制,强制输出,故障保护后,形成输出信号(OUT0∼OUT7)到 IO **互补输出**:偶数序号的 PWM 通道配置会生效,奇数序号的 PWM 通道输出为偶数通道的输出取反 **死区控制**: 1. 在 2 路互补的参考信号上插入的不同的延时 2. 必须同时配置成对的通道 x 和通道 x+1寄存器才能正确地生成死区。 3. 配置死区长度的单位是 0.5 个 PWM 定时器时钟周期 **输出极性配置** ### **强制输出控制** 1. **允许用户把参考信号配置成指定的状态** 2. **触发方式**:硬件触发还是由软件触发 3. **强制输出生效时机**:可以选择输出生效的时机。 4. 可以配置强制输出生效时通道 0∼7 输出的状态 ### **故障保护** 1. 选择外部故障输入信号是逻辑 1 生效,还是逻辑 0 生效。 2. 打开或者关闭 PWM 定时器的**外部故障**输入 3. ,打开或者关闭 PWM 定时器的**内部故障**输入 4. 一旦故障发生,那么在系统状态变化之前,PWM 输出都不会恢复。用户可以通过设置 PWMCFGx[FAULTRECTIME],选择 **PWM 恢复的时机**: 5. 用户可以选择打开一个或者多个乃至全部故障输入信号。在打开的故障输入中,**任意一个生效时,故障保护即有效。** ### 择比较器的工作模式 - 1’b0,输出比较模式,比较器可以被分配给通道,用作输出 - 1’b1,输入捕获模式,此时,比较器用来捕获输入信号的翻转,并在**翻转时保存计数器的值**(CNT 和XCNT)。 把比较器配置成输入捕获模式后,用户可以从寄存器 **CAPPOSx** 寄存器读取到 CMPx 在信号(INx)**上升沿**捕获到的计数器值;在 **CAPNEGx** 寄存器读取到 CMPx 在**下降沿**捕获到的计数器值。CAPPOSx 和 CAPNEGx 寄存器即会保存计数器寄存器的 24 位计数器(CNT)值,也会保存 4 位扩展计数器(XCNT)值 ### 三组寄存器支持**影子寄存器**: ● **计数器的起始寄存器 STA(包括 STA/XSTA)和重载寄存器 RLD**(包括 RLD/XRLD) ● 比较器 CMPx,当其在用作输出比较时 ● 控制寄存器中的 FRCMD[FRCMD] 位,即通道 0∼7(PWM 通道)的强制输出控制模式位 ### STA、RLD生效时机 1. 软件把 **SHLK [SHLK] 位置 1** 后生效,(SHLK [SHLK]是影子寄存器锁定位) 2. **实时生效**,在寄存器写之后,一个周期内生效 3. 定时器的某一个 CMP 发生匹配后生效,通过 **SHCR[CNTSHDWSEL] 选择一个比较器** 4. 影子寄存器重载触发输入 SHRLDSYNCI 上捕获到上升沿时 ### 比较寄存器cmp生效时机 1. 软件把 **SHLK [SHLK] 位置 1** 后生效 2. **实时生效**,在寄存器写之后,一个周期内生效 3. 定时器的某一个 CMP 发生匹配后生效,通过      **CMPCFGx[CMPSHDWUPT]**** 选择一个比较器** 4. 影子寄存器重载触发输入 SHRLDSYNCI 上捕获到上升沿时 ### 强制输出模式位的影子寄存器位生效 1. 软件把 **SHLK [SHLK] 位置 1** 后生效 2. **实时生效**,在寄存器写之后,一个周期内生效 3. 定时器的某一个 CMP 发生匹配后生效,通过      ** SHCR [FRCSHDWSEL] **** 选择一个比较器** 4. 影子寄存器重载触发输入 SHRLDSYNCI 上捕获到上升沿时 ## pwm 输入比较结构 ```c /** * @brief pwm compare config * */ typedef struct pwm_cmp_config {     uint32_t cmp;         /**< 比较器的值compare value */     bool enable_ex_cmp;   /**< 比较器的扩展的值enable extended compare value */ #if PWM_SOC_HRPWM_SUPPORT     bool enable_hrcmp;     /**< enable high precision pwm 使能高分辨率比较*/ #endif     uint8_t mode;         /**< pwm输出或输入捕获选择 compare work mode: pwm_cmp_mode_output_compare or pwm_cmp_mode_input_capture */     uint8_t update_trigger;  /**< 比较配置更新触发器 compare configuration update trigger */     uint8_t ex_cmp;       /**< 扩展比较值 extended compare value */     uint8_t half_clock_cmp; /**< half clock compare value*/     uint8_t jitter_cmp;     /**< 抖动比较值 jitter compare value */ #if PWM_SOC_HRPWM_SUPPORT     uint8_t hrcmp;         /**< high precision pwm */ #endif } pwm_cmp_config_t; ``` ### pwm影子寄存器生效时机 ```c /** * @brief update time of the shadow register * */ typedef enum pwm_register_update {     pwm_shadow_register_update_on_shlk = 0,     /**< 软件把 **SHLK [SHLK] 位置 1** 后生效        after software set shlk bit of shlk register*/     pwm_shadow_register_update_on_modify = 1,   /**PWM3 ###  PWM2 PWM3 强制输出高低电平测试 ```c /*   PWM2 PWM3 强制输出高低电平测试 */ void test_pwm_force_output ( void ) {         //配置引脚复用      HPM_IOC->PAD[IOC_PAD_PA26].FUNC_CTL = IOC_PA26_FUNC_CTL_PWM0_P_2;      HPM_IOC->PAD[IOC_PAD_PA27].FUNC_CTL = IOC_PA27_FUNC_CTL_PWM0_P_3;                 //强制输出时机控制--立即生效         pwm_config_force_cmd_timing ( PWM, pwm_force_immediately );         //打开强制输出         pwm_enable_pwm_sw_force_output ( PWM, 2 );//pa26-->PWM2         pwm_enable_pwm_sw_force_output ( PWM, 3 );//pa27--->PWM3         printf ( "Output high\n" );         //强制输出模式控制位         pwm_set_force_output ( PWM,                                PWM_FORCE_OUTPUT ( 2, pwm_output_1 )                                | PWM_FORCE_OUTPUT ( 3, pwm_output_1 ) );         //软件强制输出         pwm_enable_sw_force ( PWM );         board_delay_ms ( 5000 );                 printf ( "Output low\n" );         pwm_set_force_output ( PWM,                                PWM_FORCE_OUTPUT ( 2, pwm_output_0 )                                | PWM_FORCE_OUTPUT ( 3, pwm_output_0 ) );         board_delay_ms ( 5000 );         pwm_disable_sw_force ( PWM );         //关闭强制输出         pwm_disable_pwm_sw_force_output ( PWM, 2 );         pwm_disable_pwm_sw_force_output ( PWM, 3 ); } ``` ### 输出pwm波形 ````c void generate_edge_aligned_waveform ( void ) {         uint8_t cmp_index = 0;         uint32_t duty, duty_step;         bool increase_duty_cycle = true;         pwm_cmp_config_t cmp_config[2] = {0};         pwm_config_t pwm_config = {0};                 //配置通道2和3的pin复用         HPM_IOC->PAD[IOC_PAD_PA26].FUNC_CTL = IOC_PA26_FUNC_CTL_PWM0_P_2;         HPM_IOC->PAD[IOC_PAD_PA27].FUNC_CTL = IOC_PA27_FUNC_CTL_PWM0_P_3;                 //使能/关闭 PWM 定时器的计数器         pwm_stop_counter ( PWM );         reset_pwm_counter();                 pwm_get_default_pwm_config ( PWM, &pwm_config );         pwm_config.enable_output = true;         pwm_config.dead_zone_in_half_cycle = 0;         pwm_config.invert_output = false;         /*          * reload and start counter          */         pwm_set_reload ( PWM, 0, reload );//设置重载值         pwm_set_start_count ( PWM, 0, 0 );//启动定时器         /*          * config cmp = RELOAD + 1          */         cmp_config[0].mode = pwm_cmp_mode_output_compare;//输出比较模式         cmp_config[0].cmp = reload + 1;//设置比较直         cmp_config[0].update_trigger = pwm_shadow_register_update_on_hw_event;//影子寄存器更新时机  这里选择的是以某一个比较器的匹配事件作为生效时机         cmp_config[1].mode = pwm_cmp_mode_output_compare;         cmp_config[1].cmp = reload;         cmp_config[1].update_trigger = pwm_shadow_register_update_on_modify;//立即生效         /*          * config pwm as output driven by cmp 配置通道的pwm数据和匹配一个比较器          设置波形          */         if ( status_success != pwm_setup_waveform ( PWM, 2, &pwm_config, cmp_index, &cmp_config[0], 1 ) )         {                 printf ( "failed to setup waveform\n" );                 while ( 1 );         }         cmp_config[0].cmp = reload >> 1;//占空比位50         /*          * config pwm as reference          */         if ( status_success != pwm_setup_waveform ( PWM, 3, &pwm_config, cmp_index + 1, &cmp_config[0], 1 ) )         {                 printf ( "failed to setup waveform\n" );                 while ( 1 );         }         printf ( "............................\n" );     //配置比较器2的 的影子寄存器生效时机,这里选择的是以某一个比较器的匹配事件作为生效时机         pwm_load_cmp_shadow_on_match ( PWM, cmp_index + 2, &cmp_config[1] );         pwm_start_counter ( PWM );         pwm_issue_shadow_register_lock_event ( PWM );         duty_step = reload / 100;         duty = reload / 100;         increase_duty_cycle = true;         for ( uint32_t i = 0; i < TEST_LOOP; i++ )         {                 if ( increase_duty_cycle )                 {                         if ( ( duty + duty_step ) >= reload )                         {                                 increase_duty_cycle = false;                                 continue;                         }                         duty += duty_step;                 }                 else                 {                         if ( duty PAD[IOC_PAD_PA26].FUNC_CTL = IOC_PA26_FUNC_CTL_PWM0_P_2;         HPM_IOC->PAD[IOC_PAD_PA27].FUNC_CTL = IOC_PA27_FUNC_CTL_PWM0_P_3;                 //使能/关闭 PWM 定时器的计数器         pwm_stop_counter ( PWM );         reset_pwm_counter();                 pwm_get_default_pwm_config ( PWM, &pwm_config );         pwm_config.enable_output = true;         pwm_config.dead_zone_in_half_cycle = 0;         pwm_config.invert_output = false;         /*          * reload and start counter          */         pwm_set_reload ( PWM, 0, reload );//设置重载值         pwm_set_start_count ( PWM, 0, 0 );//启动定时器         /*          * config cmp = RELOAD + 1          */         cmp_config[0].mode = pwm_cmp_mode_output_compare;//输出比较模式         cmp_config[0].cmp = reload + 1;//设置比较直         cmp_config[0].update_trigger = pwm_shadow_register_update_on_modify;//影子寄存器更新时机  硬件事件后asser         cmp_config[1].mode = pwm_cmp_mode_output_compare;         cmp_config[1].cmp = reload;         cmp_config[1].update_trigger = pwm_shadow_register_update_on_modify;         /*          * config pwm as output driven by cmp 配置通道的pwm数据和匹配一个比较器          设置波形          */         if ( status_success != pwm_setup_waveform ( PWM, 2, &pwm_config, cmp_index, &cmp_config[0], 1 ) )         {                 printf ( "failed to setup waveform\n" );                 while ( 1 );         }         cmp_config[0].cmp = reload >> 1;//占空比位50         /*          * config pwm as reference          */         if ( status_success != pwm_setup_waveform ( PWM, 3, &pwm_config, cmp_index + 1, &cmp_config[0], 1 ) )         {                 printf ( "failed to setup waveform\n" );                 while ( 1 );         }         printf ( "............................\n" );         //配置选择影子寄存器生效时机         //pwm_load_cmp_shadow_on_match ( PWM, cmp_index + 2, &cmp_config[1] );         pwm_start_counter ( PWM );         pwm_issue_shadow_register_lock_event ( PWM );         duty_step = reload / 100;         duty = reload / 100;         increase_duty_cycle = true;         for ( uint32_t i = 0; i < TEST_LOOP; i++ )         {                 if ( increase_duty_cycle )                 {                         if ( ( duty + duty_step ) >= reload )                         {                                 increase_duty_cycle = false;                                 continue;                         }                         duty += duty_step;                 }                 else                 {                         if ( duty

  • 2023-12-10
  • 发表了主题帖: 先楫半导体HPM5361EVK--串口

    # 5.串口 有9 个通用异步收发器 8 个通用异步收发器位于系统电源域,称为 UART0∼7。 1 个通用异步收发器位于电源管理域,称为 PUART ## UART 的主要特性: ● 支持 5∼9 位数据长度 ● 可配置停止位:1 位,1.5 位或者 2 位 ● 可配置奇偶校验位:奇校验,偶校验,粘校验位 ● 支持 DMA 数据传输 ● 支持可配置波特率,支持独立的波特率生成时钟 ● 支持硬件流控 ● 支持奇偶校验错误,数据 FIFO 溢出等错误检测 ● **16 字节的 TXFIFO 和 RXFIFO** ● 支持各类中断 ## **UART** **发送** - UART 发送端由 TX FIFO 和 TX 移位寄存器和 TX 控制器组成。 - **TX FIFO 包含待发送的数据**,并将数据传送到 TX 移位寄存器。 - TX 移位寄存器为并行-串行转换器,把发送数据转换成串行的比特流。 - TX 控制器在发送一个数据时,会生成一个 START 位,一个可配置的奇偶校验位 PARITY 位,和一个长度可配的停止位。用户可以LCR寄存器 (Line Control Register) 来配置奇偶效验位和停止位。 - **TXFIFO 的写入口是THR寄存器 (Transmitter Holding Register)**。用户需要把FCR寄存器 (FIFO Control Register) 的 FIFOE 位置 1,来**打开 TXFIFO**。 ## **UART** **接收** - UART 接收端由 RX FIFO 和 RX 移位寄存器和 RX 控制器组成。 - RX 控制器使用波特率控制模块生成的过采样时钟,对输入的每一位进行采样,并把收到的每一位移入 RX 移   位寄存器。 - RX 移位寄存器对数据进行串行-并行转换,并把数据存入 RX FIFO。 - **RX FIFO 的读入口是RBR寄存器** (Receiver Buffer Register),用户需要把FCR寄存器 (FIFO Control Register)   的 FIFOE 位置 1,来**打开 RXFIFO**。 - RX 控制器支持检测接收数据过程中的错误,如奇偶校验位错误,停止位错误,RX FIFO 溢出等。 ## **DMA** - UART 支持发送 DMA 请求和接收 DMA 请求。 - 用户通过FCR寄存器配置 **RX FIFO** 的**触发阈值RFIFOT**,当 RX FIFO 接收的数据超过阈值时,生成 DMA 接收请求。 - 用户通过FCR寄存器配置 **TX FIFO** 的**触发阈值**TFIFOT,当 TX FIFO 的待发送数据少于阈值时,生成 DMA发送请求。 ## 串口相关数据结构 ## 1.配置结构体 ```c /** * @brief UART config */ typedef struct hpm_uart_config {     uint32_t src_freq_in_hz;                    /**< 时钟源频率Source clock frequency in Hz */     uint32_t baudrate;                          /**< 波特率Baudrate */     uint8_t num_of_stop_bits;                   /**< 停止位Number of stop bits */     uint8_t word_length;                        /**< 数据长度Word length */     uint8_t parity;                             /**< Parity */     uint8_t tx_fifo_level;                      /**< TX Fifo level */     uint8_t rx_fifo_level;                      /**< RX Fifo level */     bool dma_enable;                            /**< DMA Enable flag */     bool fifo_enable;                           /**< Fifo Enable flag */     uart_modem_config_t modem_config;           /**< Modem config */ #if defined(UART_SOC_HAS_RXLINE_IDLE_DETECTION) && (UART_SOC_HAS_RXLINE_IDLE_DETECTION == 1)     uart_rxline_idle_config_t  rxidle_config;   /**< 接收空闲配置 RX Idle configuration */ #endif #if defined(UART_SOC_HAS_TXLINE_IDLE_DETECTION) && (UART_SOC_HAS_TXLINE_IDLE_DETECTION == 1)     uart_rxline_idle_config_t  txidle_config;   /**< 发送空闲配置 TX Idle configuration */ #endif #if defined(UART_SOC_HAS_RXEN_CFG) && (UART_SOC_HAS_RXEN_CFG == 1)     bool rx_enable;                             /**< 接收使能 配置RX Enable configuration */ #endif } uart_config_t; ``` ### 工作模式枚举 ```c /** * @brief UART modem config */ typedef struct uart_modem_config {     bool auto_flow_ctrl_en;     /**< 流控使能         Auto flow control enable flag */     bool loop_back_en;          /**< 回环使能         Loop back enable flag */     bool set_rts_high;          /**< 设置rts位高        Set signal RTS level high flag */ } uart_modem_config_t; ``` ### 串口接收空闲配置结构 ```c /* 判定空闲条件枚举 */ typedef enum hpm_uart_rxline_idle_cond {     uart_rxline_idle_cond_rxline_logic_one = 0,         /**< 如果接收线路位高电平时间持续时间超过阈值,则视为空闲 Treat as idle if the RX Line high duration exceeds threshold */     uart_rxline_idle_cond_state_machine_idle = 1        /**< 如果RX状态机空闲状态持续时间超过阈值,则视为空闲 Treat as idle if the RX state machine idle state duration exceeds threshold */ } uart_rxline_idle_cond_t; /*         接收空闲配置结构 */ typedef struct hpm_uart_rxline_idle_detect_config {     bool detect_enable;                 /**< 接受空闲检测标志 RX Line Idle detection flag */     bool detect_irq_enable;             /**< 使能空闲检测标志 Enable RX Line Idle detection interrupt */     uart_rxline_idle_cond_t idle_cond;  /**< 空闲检测条件 RX Line Idle detection condition */     uint8_t threshold;                  /**< 空闲检测阈值 UART RX Line Idle detection threshold, in terms of bits */ } uart_rxline_idle_config_t; ``` ## dma ```c /* @brief Channel config */ typedef struct dma_handshake_config {     uint32_t dst;//目标地址     uint32_t src;//源地址     uint32_t size_in_byte;//数据长度     uint8_t data_width;            /*数据宽度 data width, value defined by DMA_TRANSFER_WIDTH_xxx */     uint8_t ch_index;//通道编号     bool dst_fixed;//目标地址自动增长     bool src_fixed;//源地址自动增长     bool en_infiniteloop;//使能自动循环     uint16_t interrupt_mask;//中断掩码 } dma_handshake_config_t; ``` ### 串口中断 ```c /* @brief UART interrupt IDs */ typedef enum uart_intr_id {     uart_intr_id_modem_stat = 0x0,//modem 状态     uart_intr_id_tx_slot_avail = 0x2,//2: 发送缓存寄存器空     uart_intr_id_rx_data_avail = 0x4,//4: 接收数据有效     uart_intr_id_rx_line_stat = 0x6,//6: 接收状态     uart_intr_id_rx_timeout = 0xc,//超时 } uart_intr_id_t; ``` ## 串口初始化流程 1. 初始化pin    ```c    /*            设置引脚复用为串口    */    void init_uart_pins(UART_Type *ptr)    {        if (ptr == HPM_UART0) {            HPM_IOC->PAD[IOC_PAD_PA00].FUNC_CTL = IOC_PA00_FUNC_CTL_UART0_TXD;            HPM_IOC->PAD[IOC_PAD_PA01].FUNC_CTL = IOC_PA01_FUNC_CTL_UART0_RXD;        } else if (ptr == HPM_UART2) {            HPM_IOC->PAD[IOC_PAD_PB08].FUNC_CTL = IOC_PB08_FUNC_CTL_UART2_TXD;            HPM_IOC->PAD[IOC_PAD_PB09].FUNC_CTL = IOC_PB09_FUNC_CTL_UART2_RXD;            HPM_IOC->PAD[IOC_PAD_PB10].FUNC_CTL = IOC_PB10_FUNC_CTL_UART2_DE;        } else {            ;        }    }        ```     2. 设置串口时钟    ```c    uint32_t board_init_uart_clock(UART_Type *ptr)    {        uint32_t freq = 0U;        if (ptr == HPM_UART0) {            clock_set_source_divider(clock_uart0, clk_src_osc24m, 1);            clock_add_to_group(clock_uart0, 0);            freq = clock_get_frequency(clock_uart0);        } else if (ptr == HPM_UART1) {            clock_set_source_divider(clock_uart1, clk_src_osc24m, 1);            clock_add_to_group(clock_uart1, 0);            freq = clock_get_frequency(clock_uart1);        } else if (ptr == HPM_UART2) {            clock_set_source_divider(clock_uart2, clk_src_pll0_clk2, 8);            clock_add_to_group(clock_uart2, 0);            freq = clock_get_frequency(clock_uart2);        }            return freq;    }    ``` 3. 配置串口参数    ```c    void uart_default_config(UART_Type *ptr, uart_config_t *config)    {        config->baudrate = 115200;        config->word_length = word_length_8_bits;        config->parity = parity_none;        config->num_of_stop_bits = stop_bits_1;        config->fifo_enable = true;//fifo使能        config->rx_fifo_level = uart_rx_fifo_trg_not_empty;//接收fifo触发阈值        config->tx_fifo_level = uart_tx_fifo_trg_not_full;//发送fifo触发阈值        config->dma_enable = false;//dma关闭        config->modem_config.auto_flow_ctrl_en = false;//关闭流控        config->modem_config.loop_back_en = false;//回环关闭        config->modem_config.set_rts_high = false;//rts为低    #if defined(UART_SOC_HAS_RXLINE_IDLE_DETECTION) && (UART_SOC_HAS_RXLINE_IDLE_DETECTION == 1)        /*关闭接收空闲检测*/        config->rxidle_config.detect_enable = false;        config->rxidle_config.detect_irq_enable = false;        config->rxidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;        config->rxidle_config.threshold = 10; /* 10-bit for typical UART configuration (8-N-1) */    #endif    #if defined(UART_SOC_HAS_TXLINE_IDLE_DETECTION) && (UART_SOC_HAS_TXLINE_IDLE_DETECTION == 1)        /*关闭发送空闲检测*/        config->txidle_config.detect_enable = false;        config->txidle_config.detect_irq_enable = false;        config->txidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;        config->txidle_config.threshold = 10; /* 10-bit for typical UART configuration (8-N-1) */    #endif    #if defined(UART_SOC_HAS_RXEN_CFG) && (UART_SOC_HAS_RXEN_CFG == 1)        //串口使能        config->rx_enable = true;    #endif    }    ``` 4. 修改串口默认参数    ```c    /*修改默认参数*/        config.baudrate = TEST_UART_BAUDRATE;//115200        config.fifo_enable = true; //fifo使能        config.dma_enable = true; //dma使能        config.src_freq_in_hz = clock_get_frequency(TEST_UART_CLK_NAME);//设置时钟        //接收数据空闲检测        config.rx_fifo_level = uart_rx_fifo_trg_not_empty; /* this config should not change */        config.rxidle_config.detect_enable = true;        config.rxidle_config.detect_irq_enable = true;        config.rxidle_config.idle_cond = uart_rxline_idle_cond_rxline_logic_one;        config.rxidle_config.threshold = 20U; /* 20bit */    ``` 5. 配置串口    ```c     stat = uart_init(TEST_UART, &config);        if (stat != status_success) {            printf("failed to initialize uart\n");        }    ``` 6. 使能串口中断    ```c     intc_m_enable_irq_with_priority(TEST_UART_IRQ, 1);    ``` 7. 配置dma    ```    /*    1.映射串口接收和dma通道    2.配置dma    */    ```     ## 串口使用中断接收数据示例 ```c /* * Copyright (c) 2021 HPMicro * * SPDX-License-Identifier: BSD-3-Clause * */ #include "board.h" #include "hpm_clock_drv.h" #include "hpm_uart_drv.h" void uart_isr(void) {     uint8_t c;     uint8_t irq_id = uart_get_irq_id(HPM_UART0);     if (irq_id == uart_intr_id_rx_data_avail)     {         if (status_success != uart_receive_byte(HPM_UART0, &c))         {                   }                             uart_disable_irq(HPM_UART0, uart_intr_rx_data_avail_or_timeout);             uart_write_byte(HPM_UART0,c);             uart_enable_irq(HPM_UART0, uart_intr_tx_slot_avail);                           }     else if (irq_id == uart_intr_id_tx_slot_avail)      {             uart_enable_irq(HPM_UART0, uart_intr_rx_data_avail_or_timeout);        }     } SDK_DECLARE_EXT_ISR_M(IRQn_UART0, uart_isr) void bsp_init_uart0() {     /* configure uart's pin before opening uart's clock */    // 设置gpio为串口模式       HPM_IOC->PAD[IOC_PAD_PA00].FUNC_CTL = IOC_PA00_FUNC_CTL_UART0_TXD;         HPM_IOC->PAD[IOC_PAD_PA01].FUNC_CTL = IOC_PA01_FUNC_CTL_UART0_RXD;     // 设置串口的时钟源和分频系数     clock_set_source_divider(clock_uart0, clk_src_pll0_clk0, 1);     //将串口时钟添加到一个分组     clock_add_to_group(clock_uart0, 0);     uint32_t    freq = clock_get_frequency(clock_uart0); } int main(void) {     hpm_stat_t stat;     board_init();     /* if TEST_UART is same as BOARD_CONSOLE_BASE, it has been initialized in board_init(); */    // board_init_uart(HPM_UART0);     bsp_init_uart0();     //串口的默认配置     uart_config_t config = {0};     uart_default_config(HPM_UART0, &config);     //配置fifo使能     config.fifo_enable = true;     //配置串口频率     config.src_freq_in_hz = clock_get_frequency(clock_uart0);     //串口配置     stat = uart_init(HPM_UART0, &config);     if (stat != status_success) {         /* uart failed to be initialized */         printf("failed to initialize uart\n");         while(1);     }     //使能串口中断     uart_enable_irq(HPM_UART0, uart_intr_rx_data_avail_or_timeout);     //设置串口中断优先级     intc_m_enable_irq_with_priority(IRQn_UART0, 1);     while(1)     {         __asm("wfi;\n");     }     return 0; } ```

  • 2023-11-30
  • 发表了主题帖: 先楫半导体HPM5361EVK--点亮一颗led与按键中断

    本帖最后由 chejia12 于 2023-11-30 19:42 编辑 # 先楫半导体HPM5361EVK--点亮一颗led gpio分为io控制器和gpio控制器 ## 2.1**IO 控制器 ** ### **2.1.1IOC特性** - 外设复用功能映射 - 输出回送控制 (loopback) - 模拟功能配置 - 压摆率配置 - 开漏设置 - 施密特触发器 - 上下拉配置 - 驱动能力配置 ### 2.1.2基本配置IOC_X_PAD_CTL 寄存器 - 开漏 - 施密特触发 - 上下拉电阻 - 压摆率 - 驱动能力 ### 2.1.3外设功能配置 IOC_X_FUNC_CTL 寄存器 - 输出回送功能 - 模拟功能和外设 - 功能映射(外设引脚复用) ### 2.1.5涉及的数据结构 ```c typedef struct {     struct {         __RW uint32_t FUNC_CTL;                /* 0x0: ALT SELECT */         __RW uint32_t PAD_CTL;                 /* 0x4: PAD SETTINGS */     } PAD[456]; } IOC_Type; ``` ### 电气属性相关的宏定义 1. 回环使能 2. 模拟输入使能 3. 引脚复用选择ALT0~ALT31 4. 施密特触发使能 5. 上下拉电阻大小选择 6. 上下拉选择 7. 上下拉使能 8. 电平保持使能 9. 开漏使能 10. 摇摆率高低速选择 11. 引脚速度选择4种 12. 驱动能力选择 ```c /* Bitfield definition for register of struct array PAD: FUNC_CTL */ /* * LOOP_BACK (RW) * * force input on * 0: disable * 1: enable */ #define IOC_PAD_FUNC_CTL_LOOP_BACK_MASK (0x10000UL) #define IOC_PAD_FUNC_CTL_LOOP_BACK_SHIFT (16U) #define IOC_PAD_FUNC_CTL_LOOP_BACK_SET(x) (((uint32_t)(x) > IOC_PAD_FUNC_CTL_LOOP_BACK_SHIFT) /* * ANALOG (RW) * * select analog pin in pad * 0: disable * 1: enable */ #define IOC_PAD_FUNC_CTL_ANALOG_MASK (0x100U) #define IOC_PAD_FUNC_CTL_ANALOG_SHIFT (8U) #define IOC_PAD_FUNC_CTL_ANALOG_SET(x) (((uint32_t)(x) > IOC_PAD_FUNC_CTL_ANALOG_SHIFT) /* * ALT_SELECT (RW) * * alt select * 0: ALT0 * 1: ALT1 * ... * 31:ALT31 */ #define IOC_PAD_FUNC_CTL_ALT_SELECT_MASK (0x1FU) #define IOC_PAD_FUNC_CTL_ALT_SELECT_SHIFT (0U) #define IOC_PAD_FUNC_CTL_ALT_SELECT_SET(x) (((uint32_t)(x) > IOC_PAD_FUNC_CTL_ALT_SELECT_SHIFT) /* Bitfield definition for register of struct array PAD: PAD_CTL */ /* * HYS (RW) * * schmitt trigger enable * 0: disable * 1: enable */ #define IOC_PAD_PAD_CTL_HYS_MASK (0x1000000UL) #define IOC_PAD_PAD_CTL_HYS_SHIFT (24U) #define IOC_PAD_PAD_CTL_HYS_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_HYS_SHIFT) /* * PRS (RW) * * select pull up/down internal resistance strength: * For pull down, only have 100 Kohm resistance * For pull up: * 00: 100 KOhm * 01: 47 KOhm * 10: 22 KOhm * 11: 22 KOhm */ #define IOC_PAD_PAD_CTL_PRS_MASK (0x300000UL) #define IOC_PAD_PAD_CTL_PRS_SHIFT (20U) #define IOC_PAD_PAD_CTL_PRS_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_PRS_SHIFT) /* * PS (RW) * * pull select * 0: pull down * 1: pull up */ #define IOC_PAD_PAD_CTL_PS_MASK (0x40000UL) #define IOC_PAD_PAD_CTL_PS_SHIFT (18U) #define IOC_PAD_PAD_CTL_PS_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_PS_SHIFT) /* * PE (RW) * * pull enable * 0: pull disable * 1: pull enable */ #define IOC_PAD_PAD_CTL_PE_MASK (0x20000UL) #define IOC_PAD_PAD_CTL_PE_SHIFT (17U) #define IOC_PAD_PAD_CTL_PE_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_PE_SHIFT) /* * KE (RW) * * keeper capability enable * 0: keeper disable * 1: keeper enable */ #define IOC_PAD_PAD_CTL_KE_MASK (0x10000UL) #define IOC_PAD_PAD_CTL_KE_SHIFT (16U) #define IOC_PAD_PAD_CTL_KE_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_KE_SHIFT) /* * OD (RW) * * open drain * 0: open drain disable * 1: open drain enable */ #define IOC_PAD_PAD_CTL_OD_MASK (0x100U) #define IOC_PAD_PAD_CTL_OD_SHIFT (8U) #define IOC_PAD_PAD_CTL_OD_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_OD_SHIFT) /* * SR (RW) * * slew rate * 0: Slow slew rate * 1: Fast slew rate */ #define IOC_PAD_PAD_CTL_SR_MASK (0x40U) #define IOC_PAD_PAD_CTL_SR_SHIFT (6U) #define IOC_PAD_PAD_CTL_SR_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_SR_SHIFT) /* * SPD (RW) * * additional 2-bit slew rate to select IO cell operation frequency range with reduced switching noise * 00: Slow frequency slew rate(50Mhz) * 01: Medium frequency slew rate(100 Mhz) * 10: Fast frequency slew rate(150 Mhz) * 11: Max frequency slew rate(200Mhz) */ #define IOC_PAD_PAD_CTL_SPD_MASK (0x30U) #define IOC_PAD_PAD_CTL_SPD_SHIFT (4U) #define IOC_PAD_PAD_CTL_SPD_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_SPD_SHIFT) /* * DS (RW) * * drive strength * 1.8V Mode: * 000: 260 Ohm * 001: 260 Ohm * 010: 130 Ohm * 011: 88 Ohm * 100: 65 Ohm * 101: 52 Ohm * 110: 43 Ohm * 111: 37 Ohm * 3.3V Mode: * 000: 157 Ohm * 001: 157 Ohm * 010: 78 Ohm * 011: 53 Ohm * 100: 39 Ohm * 101: 32 Ohm * 110: 26 Ohm * 111: 23 Ohm */ #define IOC_PAD_PAD_CTL_DS_MASK (0x7U) #define IOC_PAD_PAD_CTL_DS_SHIFT (0U) #define IOC_PAD_PAD_CTL_DS_SET(x) (((uint32_t)(x) > IOC_PAD_PAD_CTL_DS_SHIFT) ``` ## 2.2gpio控制器 ### **2.2.1特性总结** 本章节介绍 GPIO 控制器的主要特性: - 配置 IO 作为输入或者输出 - 读取 IO 输入的状态 - 设置 IO 的输出 - 原子化操作设置 IO 输出高,输出低,翻转 GPIO,PGPIO 支持配置 GPIO 中断,FGPIO0 不支持生成中断。 ### 2.2.2GPIO** **控制** OE:控制gpio方向 DO:控制输出电平 DI 寄存器可以实现 IO 监听和状态读取 原子化操作寄存器 - 输出高寄存器 SET - 输出低寄存器 CLEAR - 翻转寄存器 TOGGLE ### 2.2.3GPIO中断 - IE 寄存器打开 GPIO 中断 - TP 寄存器来指定中断的类型;置 1,表示中断由边沿触发,置0,表示中断由电平触发。 - PL 寄存器来指定中断的极性;位置 1,表示中断由下降沿或者低电平触发,置 0,表示中断由上升沿或高电平触发 - IF 寄存器来查询中断的状态,对应标志位置 1,表示对应 IO 有中断待处理;位写 1,可以清除这个标志位 - GPIO 控制器支持在检测到上升沿或下降沿生成中断,也支持双沿或单沿触发模式。 - GPIO 支持生成异步中断,异步中断允许在系统时钟异常时生成中断。 ### 2.2.4相关的数据结构 ```c typedef struct {     struct {         __R  uint32_t VALUE;                   /* 0x0: GPIO input value IO数据读取*/         __R  uint8_t  RESERVED0[12];           /* 0x4 - 0xF: Reserved */     } DI[16];     struct {         __RW uint32_t VALUE;                   /* 0x100: GPIO output value IO数据写入 */         __RW uint32_t SET;                     /* 0x104: GPIO output set */         __RW uint32_t CLEAR;                   /* 0x108: GPIO output clear */         __RW uint32_t TOGGLE;                  /* 0x10C: GPIO output toggle */     } DO[16];     struct {         __RW uint32_t VALUE;                   /* 0x200: GPIO direction value IO方向写入*/         __RW uint32_t SET;                     /* 0x204: GPIO direction set */         __RW uint32_t CLEAR;                   /* 0x208: GPIO direction clear */         __RW uint32_t TOGGLE;                  /* 0x20C: GPIO direction toggle */     } OE[16];     struct {         __W  uint32_t VALUE;                   /* 0x300: GPIO interrupt flag value 中断标志*/         __R  uint8_t  RESERVED0[12];           /* 0x304 - 0x30F: Reserved */     } IF[16];     struct {         __RW uint32_t VALUE;                   /* 0x400: GPIO interrupt enable value 中断使能控制*/         __RW uint32_t SET;                     /* 0x404: GPIO interrupt enable set */         __RW uint32_t CLEAR;                   /* 0x408: GPIO interrupt enable clear */         __RW uint32_t TOGGLE;                  /* 0x40C: GPIO interrupt enable toggle */     } IE[16];     struct {         __RW uint32_t VALUE;                   /* 0x500: GPIO interrupt polarity value中断极性设置 */         __RW uint32_t SET;                     /* 0x504: GPIO interrupt polarity set */         __RW uint32_t CLEAR;                   /* 0x508: GPIO interrupt polarity clear */         __RW uint32_t TOGGLE;                  /* 0x50C: GPIO interrupt polarity toggle */     } PL[16];     struct {         __RW uint32_t VALUE;                   /* 0x600: GPIO interrupt type value 中断类型设置*/         __RW uint32_t SET;                     /* 0x604: GPIO interrupt type set */         __RW uint32_t CLEAR;                   /* 0x608: GPIO interrupt type clear */         __RW uint32_t TOGGLE;                  /* 0x60C: GPIO interrupt type toggle */     } TP[16];     struct {         __RW uint32_t VALUE;                   /* 0x700: GPIO interrupt asynchronous value 中断异步使能*/         __RW uint32_t SET;                     /* 0x704: GPIO interrupt asynchronous set */         __RW uint32_t CLEAR;                   /* 0x708: GPIO interrupt asynchronous clear */         __RW uint32_t TOGGLE;                  /* 0x70C: GPIO interrupt asynchronous toggle */     } AS[16];     struct {         __RW uint32_t VALUE;                   /* 0x800: GPIO dual edge interrupt enable value 中断双边沿使能触发*/         __RW uint32_t SET;                     /* 0x804: GPIO dual edge interrupt enable set */         __RW uint32_t CLEAR;                   /* 0x808: GPIO dual edge interrupt enable clear */         __RW uint32_t TOGGLE;                  /* 0x80C: GPIO dual edge interrupt enable toggle */     } PD[16]; } GPIO_Type; ``` ## LED使用场景的配置方法 1. 配置复用 2. 配置电气属性;    ```c    void init_gpio_pins(void)    {        /* configure pad setting: pull enable and pull up, schmitt trigger enable */        /* enable schmitt trigger to eliminate jitter of pin used as button */            /* Button 上下拉使能;上拉;施密特触发使能 */        uint32_t pad_ctl = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_HYS_SET(1);        HPM_IOC->PAD[IOC_PAD_PA09].FUNC_CTL = IOC_PA09_FUNC_CTL_GPIO_A_09;        HPM_IOC->PAD[IOC_PAD_PA09].PAD_CTL = pad_ctl;    }    ``` 3. 设置gpio属性    ```c    //输入    gpio_set_pin_input(BOARD_APP_GPIO_CTRL, BOARD_APP_GPIO_INDEX, BOARD_APP_GPIO_PIN);    //输出    gpio_write_pin(HPM_GPIO0, GPIO_DI_GPIOA,23, 1);    ``` 4. LED电平翻转    ```c     gpio_toggle_pin(HPM_GPIO0, GPIO_DI_GPIOA,23, 1);    ``` ## LED实例 ```c /*   配置gpio */ void bsp_init_gpio_pins(void) {     /*       上下拉使能,上拉,使能施密特触发器           configure pad setting: pull enable and pull up, schmitt trigger enable */     /* enable schmitt trigger to eliminate jitter of pin used as button */     /* Button */     uint32_t pad_ctl = IOC_PAD_PAD_CTL_PE_SET(1) | IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_HYS_SET(1);     HPM_IOC->PAD[IOC_PAD_PA23].FUNC_CTL = IOC_PA23_FUNC_CTL_GPIO_A_23;     HPM_IOC->PAD[IOC_PAD_PA23].PAD_CTL = pad_ctl;       } /*         配置gpio方向   in_out=1:out   in_out=1:in */ void bsp_init_gpio(int in_out) {   if(in_out)   {     gpio_set_pin_output(HPM_GPIO0, GPIO_DI_GPIOA, IOC_PAD_PA23);   }   else{     gpio_set_pin_input(HPM_GPIO0, GPIO_DI_GPIOA, IOC_PAD_PA23);   }    } int main(void) {     board_init();    bsp_init_gpio_pins();    bsp_init_gpio(1);         printf("gpio example\n");     gpio_write_pin(HPM_GPIO0, GPIO_DI_GPIOA, IOC_PAD_PA23,1);     for (uint32_t i = 0; i < 10; i++) {         gpio_toggle_pin(HPM_GPIO0, GPIO_DI_GPIOA, IOC_PAD_PA23);         board_delay_ms(500);         gpio_toggle_pin(HPM_GPIO0, GPIO_DI_GPIOA, IOC_PAD_PA23);         board_delay_ms(500);         printf("toggling led %u/%u times\n", i + 1, 10);     } while (1);     return 0; } ``` ## 按键中断实例 ```c #include "board.h" #include "hpm_gpio_drv.h" void inti_key_int(void) {      gpio_interrupt_trigger_t trigger;     gpio_set_pin_output(HPM_GPIO0, GPIO_DI_GPIOA,23);     gpio_set_pin_input(HPM_GPIO0, GPIO_DI_GPIOA,9);     trigger = gpio_interrupt_trigger_edge_both;         //配置中断参数     gpio_config_pin_interrupt(HPM_GPIO0, GPIO_DI_GPIOA,9, trigger);         //使能中断     gpio_enable_pin_interrupt(HPM_GPIO0, GPIO_DI_GPIOA,9);         //设置中断优先级     intc_m_enable_irq_with_priority(IRQn_GPIO0_A, 1);     }                                void isr_gpio(void) {         //清除中断标志     gpio_clear_pin_interrupt_flag(HPM_GPIO0, GPIO_DI_GPIOA,9);     gpio_toggle_pin(HPM_GPIO0, GPIO_DI_GPIOA,23);     printf("toggle led pin output\n");     if (gpio_read_pin(HPM_GPIO0, GPIO_DI_GPIOA,9) == false) {         printf("user key pressed\n");     } else {         printf("user key released\n");     } }                                                              //注册中断处理函数 SDK_DECLARE_EXT_ISR_M(IRQn_GPIO0_A, isr_gpio) int main(void) {     board_init();     board_init_gpio_pins();     inti_key_int();     printf("gpio example\n");         while (1);     return 0; } ``` 寄存器分组 ```c #define GPIO_DI_GPIOA (0UL) #define GPIO_DI_GPIOB (1UL) #define GPIO_DI_GPIOC (2UL) #define GPIO_DI_GPIOD (3UL) #define GPIO_DI_GPIOE (4UL) #define GPIO_DI_GPIOF (5UL) #define GPIO_DI_GPIOX (13UL) #define GPIO_DI_GPIOY (14UL) #define GPIO_DI_GPIOZ (15UL) ``` ## gpio触发结构体 ```c /** * @brief Interrupt trigger type */ typedef enum gpio_interrupt_trigger {     gpio_interrupt_trigger_level_high = 0,     gpio_interrupt_trigger_level_low,     gpio_interrupt_trigger_edge_rising,     gpio_interrupt_trigger_edge_falling, #if defined(GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT) && (GPIO_SOC_HAS_EDGE_BOTH_INTERRUPT == 1)     gpio_interrupt_trigger_edge_both, #endif } gpio_interrupt_trigger_t; ```

  • 发表了主题帖: 先楫半导体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)](https://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寄存器观察窗口

最近访客

< 1/3 >

统计信息

已有60人来访过

  • 芯积分:148
  • 好友:--
  • 主题:22
  • 回复:15

留言

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


现在还没有留言