CH32V203的一些踩坑记录
前言
CH32V203是沁恒推出的一款RISCV单片机,使用了他们自己开发的青稞内核,沁恒之前还做过ARM单片机,可能比较小众,并没有怎么听过,对沁恒的认知更多的是他们制作的一些接口芯片,例如CH340之类的串口芯片。
沁恒以V和F来区分RISCV和ARM内核的产品,当然还有一些CH57x、CH58x之类的蓝牙芯片,内核也是使用的RISCV。
沁恒提供了这些MCU的例程里包括了FreeRTOS,TencentOS、HarmonyOS、RT-Thread,我主要使用FreeRTOS,其他的操作系统没有怎么了解过,而沁恒没有自己提供IDE,而是一家叫做MountRiver Studio的工作室提供的IDE(魔改Esclipse)和工具链,工具链是GCC,但是他们修改了GCC,其实按GPL协议,他们应该开源自己的GCC,但是并没有,还有被修改的OpenOCD,沁恒也没有开源,非常的让人疑惑。
踩到的坑
中断声明时奇怪的定义
上文提到了GCC被修改了,修改的主要目的就是加入沁恒定义的硬件压栈声明,像是下面提供的这样。
void HardFault_Handler(void) __attribute__((interrupt())); //软件压栈
void USART1_IRQHandler(void)__attribute__((interrupt( wch-interrupt-fast ))); //硬件压栈
非常奇怪的声明,想要搞清楚这些,必须去看沁恒的青稞内核手册。
里面提到了使用硬件压栈的时候需要这样声明,但是这个硬件压栈因为未知原因,可能会导致错误。
我在CH32V303和CH32V203上都开启过硬件压栈测试,可能是因为FreeRTOS或者其他原因,使用硬件压栈会在203上出错。
里面是有提到OS一般使用软件堆栈,还有不同的内核压栈数不太一样,如果不是对时间特别敏感,应该可以都走软件压栈吧?对时钟周期要求不是太高的情况下。
RISCV的特权模式以及浮点单元?
我对CPU内核了解的内容很少,现在大概知道是RISCV有几个模式,用户模式,监督模式,机器模式,其中机器模式的权限是最高的,用户模式的权限是最低的,FreeRTOS适配的RISCV是直接运行在机器模式上的,在移植RTOS的时候需要注意一下这点,所以我们需要让MCU保持在机器模式。
这里是官方的CH32V203 RTOS例程里的Startup File里定义的Mstatus寄存器初始值,其中只定义了MPP寄存器的值为0x03。
I2C发送地址的奇妙函数
/*********************************************************************
* @fn I2C_Send7bitAddress
*
* @brief Transmits the address byte to select the slave device.
*
* @param I2Cx - where x can be 1 or 2 to select the I2C peripheral.
* Address - specifies the slave address which will be transmitted.
* I2C_Direction - specifies whether the I2C device will be a
* Transmitter or a Receiver.
* I2C_Direction_Transmitter - Transmitter mode.
* I2C_Direction_Receiver - Receiver mode.
*
* @return none
*/
void I2C_Send7bitAddress(I2C_TypeDef *I2Cx, uint8_t Address, uint8_t I2C_Direction)
{
if(I2C_Direction != I2C_Direction_Transmitter)
{
Address |= OADDR1_ADD0_Set;
}
else
{
Address &= OADDR1_ADD0_Reset;
}
I2Cx->DATAR = Address;
}
奇妙的函数,我不知道沁恒程序员写这玩意的时候精神状态是什么样的,Send7BitAddress,光看函数名我以为要我给一个7Bit的I2C地址呢,试了若干次,在怀疑硬件是否有问题,然后我点开了这个函数.....合着你Send的是8Bit Address,还|/&一下最后一位,来标志方向啊...... 那我要你干什么,为什么我不自己构造呢?