3 February 2025
I have sent a brief summary of the RM errata to WCH via their technical support submission page. As they are currently celebrating the Lunar New Year, I don’t expect an immediate response.
Referring to Reference Manual v1.8:
On p. 73, Section 8.3.2.2 External Interrupt Configuration Register 1 (AFIO_EXTICR1), the value for assigning PB pins to the EXTI inputs is incorrect.
Per the RM:
00: xth pin of the PA pin.
10: xth pin of the PB pin.
11: xth pin of the PC pin.
Others: Reserved.
But the correct value for PB is 01, not 10.
I have code to demonstrate this issue if you would like to see it.
The value for assigning PA is correct, but I have not tested PC.
So now on to a more informative HardFault handler, in the hopes that I will never need it. The interesting part of this is the formatted hexadecimal printing routine, usart_puthex. Previously, I had a hierarchy of puthex, puthex2, puthex4 and puthex8 routines, but this one does all that and offers optional ‘0x’ prefixing and a variable length of 1-8 characters, depending on what you need. I allocated a little more space on the stack and used that as a string buffer to place the characters after I converted the last 4 bits of the value to an ASCII hexadecimal digit, then shifted the value to the right by four bits, for as many digits as was requested.
I haven’t tested the usart_puthex function extensively yet, but it seems to do the trick.
So now the HardFault handler should print out a message in the format “HardFault 0x<mcause> @ 0x<mepc> [HALT]”, where mcause and mepc are the values of the CSRs at that time.
Now I just have to induce a HardFault on purpose to test it. I use the following code:
.word 0 # *** debug *** induce illegal instruction trap
In RISC-V, any instruction of all ones or all zeros is considered to be an ‘illegal operation’. My trap works, and prints this on the console:
HardFault 0x00000002 @ 0x00000140 [HALT]
Which is precisely correct. Since the upper-most bit of the cause is zero, the lower 31 bits constitute the exception code, which in this case is ‘illegal instruction’. The address corresponds exactly with the location of the bad code in the program.
The only problem with this solution is that since it relies on the USART to transmit a message, it can only effectively be of use for errors after the USART is initialized. One solution would be to check the USART1EN bit to see if USART1’s peripheral clock has yet to be enabled, and if it has, to then check the UE bit to see if the peripheral has been initialized, then proceed with the messaging. It captures the important CSRs at the beginning of the handler in any case.
Now it should be time to set up the OLED interface and USB controller to get the framework for this project fully underway.