- 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寄存器观察窗口