合宙Air 105 学习
-
C语言开发 使用Keil 编写代码
GPIO 引脚
-
GPIO 端口的重映射
// 疑惑点, 关于GPIO_Remap_0 这个问题,如果不是看原理图或者 Demo的宏定义命名,根本不知道它映射的什么端口 void GPIO_PinRemapConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_RemapTypeDef GPIO_Remap){} // 端口映射 map 映射对象为GPIO_Remap_0、1、2、3 // 目前案例中,要求是把GPIO 映射成 Uart
1
-
IER 中断使能寄存器
// 下方截取代码部分片段,中断 if (DISABLE != UART_FIFOInitStruct->FIFO_TX_TriggerIntEnable) { UARTx->OFFSET_4.IER |= UART_IER_PTIME; } else { UARTx->OFFSET_4.IER &= ~UART_IER_PTIME; }
-
使用 Jlink 仿真器 报错
Error: Flash* Download failed - "Cortex-M4"
# 解决经验 目前遇到的这个问题点在于Target 的ROM 和RAM 地址问题 导致Jlink设备不识别Cortex 的CPU , 因此按照官方的工程设置Target 的地址
TODO:// 读GPIO 串口 SPI
TODO://
- 按键输入, GPIO 按键输入
- UART 串口
- SPI
- I2C
- GPIO 模拟串口,实现半双工通信
GPIO 按键输入
-
Air105 没看到GPIO 的中断向量函数
// Air 105 芯片对GPIO 端口的电平操作是通过置位/复位进行操作 (而非端口寄存器)。 void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // 我感觉 Air105 的库没有 GPIO 的中断服务函数。 /* 在使用Air105 C库开发的时候,没有GPIO 的中断,导致要监听一个按键时,需要用一个循环不断扫描它。 */
-
GPIO 输入函数
// 监听GPIO A...F 的pin 输入的数 uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // 监听GPIO A...F 到底是哪一个pin 在输入 uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
-
使用端口重映射,映射口应该可以自定义(但多个外设不能重复)。
GpioA_10.GPIO_Pin = GPIO_Pin_10; GpioA_10.GPIO_Mode = GPIO_Mode_IPU; // GPIO 输入 GpioA_10.GPIO_Remap = GPIO_Remap_3; // GPIO 重新映射' GPIO_PinRemapConfig(GPIOC, GPIO_Pin_1, GPIO_Remap_1); // 根据端口引脚来映射成uart 端口
-
主要踩坑的地方
1. SPI 映射的引脚问题 2. HSPI 高速SPI 映射的引脚可不是中间的SPIM0 ,而是旁边的排针。。。 3. GPIO_InitStruct.GPIO_Remap = GPIO_Remap_CS; 哪怕前面 Reamap 把这个引脚重映射了之后,这个函数也不能少,emmm 因为我前面结构体没用官方函数初始化 4. SPI 必须发送数据的时候时钟引脚才会有电压周期变化。(这一点很坑)我以为时钟会一直变化,结果不发数据他就不动。。。
UART 说明
-
在使用uart 串口中断时,遇到按照常理配置了但串口不发送东西的问题
TIP: 别看这里这么简单排错,但是没有文档的时候又有BUG( 你根本找不到错误点 ),会把你恶心坏的
// 最后找出原因,GPIO 重映射的问题, 一个串口对应一个GPIO_Remap_ ,该问题点官方文档并未说明,且未说明Remap 应该映射的引脚。 最后还是自己试出来的。 GPIO_PinRemapConfig(GPIOD, GPIO_Pin_12, GPIO_Remap_0); // GPIO 引脚的映射 这里给个引脚映射说明 GPIO_Remap_3 ----> Uart1 PC1--tx PC0---rx GPIO_Remap_0 ----> Uart2 PD13--tx PD12---rx GPIO_Remap_2 ----> Uart3 PE9--tx PE8--rx //默认 GPIO_Remap_0 ----> Uart0 PA1 PA0
-
串口发送字符串的方法( 在合宙Air105 中,发送字符串被封装成FIFO 相关的结构体配置 )
在stm32F4系列中,可以判断寄存器标志位,但在air105 将其封装为
UART_FIFOInitTypeDef UART_FIFOInitStruct; UART_FIFOInitStruct.FIFO_Enable = ENABLE; UART_FIFOInitStruct.FIFO_DMA_Mode = UART_FIFO_DMA_Mode_1; UART_FIFOInitStruct.FIFO_RX_Trigger = UART_FIFO_RX_Trigger_1_4_Full; UART_FIFOInitStruct.FIFO_TX_Trigger = UART_FIFO_TX_Trigger_2_Chars; UART_FIFOInitStruct.FIFO_TX_TriggerIntEnable = ENABLE;
-
ring_buffer 环形队列缓冲区 github参考代码仓库 参考示例理论文档
// 作用:用于接收串口发送过来的长字符串,
SPI 使用
-
void SPI_Init(SPI_TypeDef SPIx, SPI_InitTypeDef SPI_InitStruct); 函数
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
-
HSPI 高速SPI 映射口
SPI0_CSN | PB13 | |
SPI0_CL | PB12 | |
SPI0_MI | PB15 | |
SPI0_MO | PB14 |
-
SPI2 映射
// HSPI0 judge_GPIO_REMAP(2,1); // 高速spi0 专用 SPI引脚映射为 GPIO_Remap_2, CS片选引脚映射为1 // 这是普通的 SPI0 GPIO_PinRemapConfig(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15, GPIO_Remap_0); //SPI1 // SPI2 可用 GPIO_PinRemapConfig(GPIOB, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5, GPIO_Remap_0); iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 8052 -j DNAT --to 172.16.2.11:4
中断遇到的问题
下方是中断遇到的2个不同的函数,解释说明
// 这两个函数都一样,只不过一个是ST 公司做的,一个是ARM 公司做的。(但在air105 中得使用ST 公司的,也就是core_cm4.h 中的函数 )
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_0); // 这个时core_cm4.h 中的函数 设置中断优先级分组方式
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 这个misc.c 中的函数 设置中断优先级分组
中断服务函数被不断循环
// 1.如果按住PC3 按键再上电,设备就不会进入中断服务函数, 如果松开,他就一直打印中断服务函数的东西。
// 2.如果直接上电,它就直接打印
排查原因:
中断没到来的时候不打印输出,但是中断一到就一直循环输出,说明这次中断标志位没有重置,导致系统以为下次中断也到了。因此要在中断服务函数中添加如下的清除函数。
EXTI_ClearITPendingBit(EXTI_Line0);
关于固件烧写的一个案例
-
固件烧写入Flash 因为时钟或者别的代码部分可能更改了PC3 的设置(SW 烧录引脚),导致后续使用Jlink 识别不了芯片。( 解决办法:使用合宙usb 刷入一个初始化soc 再使用Keil 烧录固件 )
找到原因: 因为我使用过
SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_ALL, ENABLE); // 外设时钟复位
导致仿真器识别不了要烧写的芯片。可能是把时钟给复位了
ThreadX
-
对于threadx 是应用层的框架,移植到stm 单片机上,他不会对底层有影响,
而是需要修改的部分是:
1.Vector向量表的修改。
2.告诉上层ThreadX 中断需要执行什么函数。因此:
Threadx 并不关心stm32 单片机底层寄存器之类的地址问题。ThreadX 可以理解成一个死循环,在死循环中会有一种机制,将各类的循环分割开来,并设有优先级。如果你要使用底层GPIO 或者别的外设,还是像以前一样操作库函数 或者直接操作GPIO。
-
threadX 移植中遇到的困难:
- 系统中断函数的设置问题。
- 汇编语言报错????而且是注释部分
/**/
也报错( 可是这是微软官方给的汇编配置文件啊 )
-
使用AC6 编译,就不会出现那么多报错。但是可能Air105 的固件库不支持AC6 编译
../../Libraries/CMSIS/Include\core_cm4.h(94): note: expanded from macro '__ASM' ../../Libraries/Air105_StdPeriph_Driver/src/air105_sysctrl.c(175): error: expected identifier or '(' __STATIC_INLINE __ASM void SYSCTRL_Sleep(void)
-
回到keil 目录下的AC5 编译报错: 是
tx_thread_schedule.s
提示寄存器超过最大数量限制。Keil 编译器报错 LDM/STM instruction exceeds maximum register count 5 allowed with --split_ldm
解决办法:
根据chatGPT 提供的思路,修改汇编语言,( 我是不懂汇编的,可能只单纯能猜出汇编中部分代码是干什么的 ),
; 报错点1 ;STMDB r12!, {r4-r11} ; Save its remaining registers 原始代码 STMDB r12!, {r4-r7} STMDB r12!, {r8-r11} ; 报错点2 ;LDMIA r12!, {r4-r11} ; Recover thread's registers 原始代码 LDMIA r12!, {r4-r7} ; Restore r4-r7 LDMIA r12!, {r8-r11} ; Restore r8-r11
在ThreadX的tx_thread_schedule.s文件中,STMDB r12!, {r4-r11}是对寄存器的保存操作,而不是声明或初始化操作。 该指令用于将寄存器r4到r11的值保存到内存中,同时递减栈指针r12的值,以便为将来的恢复操作留出空间。STMDB是"Store Multiple Decrement Before"的缩写,表示先递减栈指针,再存储多个寄存器的值。 在ThreadX的上下文切换中,寄存器的保存和恢复是为了保存和恢复线程的上下文信息,以确保线程切换后能够正确恢复执行。在调度器切换到下一个线程之前,当前线程的寄存器状态被保存到其线程控制块(TCB)中,以便下次切换回该线程时能够正确恢复执行。 请注意,具体的寄存器使用和保存方式可能因处理器架构和ThreadX的移植实现而有所不同,以上解释是一般情况下的典型用法。对于特定的移植和平台,请参考相关的移植文档或具体的代码实现。