This is a continuation of some of the comments I put into the RTC keyboards thread:
And maybe also implied in a few other threads.
Some of the examples shown have a timer and in the callback code they do something like:
Serial.print("Interrupt") and only the first character "I" shows up and the program hangs.
I believe in the case of the R4 Wifi with NO_USB defined the Serial.print uses the UART1 object
I believe the Serial.print(...) calls one of the two methods:
size_t UART::write(uint8_t c) {
/* -------------------------------------------------------------------------- */
if(init_ok) {
tx_done = false;
R_SCI_UART_Write(&uart_ctrl, &c, 1);
while (!tx_done) {}
return 1;
}
else {
return 0;
}
}
size_t UART::write(uint8_t* c, size_t len) {
if(init_ok) {
tx_done = false;
R_SCI_UART_Write(&uart_ctrl, c, len);
while (!tx_done) {}
return len;
}
else {
return 0;
}
}
And in either case they will try wait for the entire transfer to complete before returning. That is tx_done will only be set to true in the ISR callback:
void UART::WrapperCallback(uart_callback_args_t *p_args) {
/* -------------------------------------------------------------------------- */
uint32_t channel = p_args->channel;
UART *uart_ptr = UART::g_uarts[channel];
if(uart_ptr == nullptr) {
return;
}
...
case UART_EVENT_TX_COMPLETE:
case UART_EVENT_TX_DATA_EMPTY:
{
//uint8_t to_enqueue = uart_ptr->txBuffer.available() < uart_ptr->uart_ctrl.fifo_depth ? uart_ptr->txBuffer.available() : uart_ptr->uart_ctrl.fifo_depth;
//while (to_enqueue) {
uart_ptr->tx_done = true;
break;
}
case UART_EVENT_RX_CHAR:
Maybe slightly lying here, it will clear it with two case, not sure if that is an issue..
And if I am reading the IRQ code correctly (IRQManager.cpp)
#define ETHERNET_PRIORITY 12
#define SDCARD_ACCESS_PRIORITY 10
#define SDCARD_DMA_REQ_PRIORITY 10
#define SDCARD_CARD_PRIORITY 12
#define EXTERNAL_PIN_PRIORITY 12
#define UART_SCI_PRIORITY 12
#define USB_PRIORITY 12
#define AGT_PRIORITY 14
#define RTC_PRIORITY 12
#define I2C_MASTER_PRIORITY 12
#define I2C_SLAVE_PRIORITY 12
#define SPI_MASTER_PRIORITY 6
#define DMA_PRIORITY 12
#define TIMER_PRIORITY 8
#define ADC_PRIORITY 12
#define CAN_PRIORITY 12
#define CANFD_PRIORITY 12
#define FIRST_INT_SLOT_FREE 0
And this is following the Arm M3/M4 standard for NVIC, I am assuming that lower priority numbers are higher priority...
And guessing Timer is runnning at Priority 8 and UART at 12 so it will not be called while in the Timer interrupt.
Not sure what best approach here would be, but some possibilities that can maybe be tried:
a) add TX queue and calls to know how much can add before it will have to wait.
b) Try changing the priority for UART.
c) Detect if priority of current code is higher (lower value) than the ISR and either temporarily boast the priority of the IRQ handler, or put code in place that detects the same stuff that the ISR is detecting and process it in the wait code.
...
z) Punt.
If it were me, I would probably do a combination of several of these, like I did with some other boards, but...
Thoughts? Am I missing something? Should this be raised as an issue in github?
Kurt