Make printf work in ISRs with interrupt driven UART driver

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Make printf work in ISRs with interrupt driven UART driver

Jump to solution
2,002 Views
trailman
Contributor V

I use interrupt driven UART driver ("ittya:") on my project and wanted to have unexpected exception beeing displayed.

 

First, in the mqx/source/bsp/<myboard>/init_bsp.c, I added 

   _int_install_unexpected_isr();

to set the default handler for unexpected ISRs; this is  _int_unexpected_isr() defined in mqx/source/psp/coldfire/int_unx.c

But as said in this file " This default I/O must NOT be an interrupt drive I/O channel"

 

However, with a very small change to the UART driver this works fine. The trick is : when printf is called from an ISR, send the characters directly to the UART.

For this, just edit

mqx/source/io/serial/int/serl_int.c

to add the following lines at the beginning of _io_serial_int_putc_internal()  (just after /* End CR 388 */) :

   if (_io_serial_int_write_force_polled_mode) {
       /* directly write to UART, bypassing normal interrupt driven code */
       int_io_dev_ptr->DEV_PUTC(int_io_dev_ptr, c);
       return;
   }

Then add to mqx/source/fio/io_util.c :

boolean _io_serial_int_write_force_polled_mode = FALSE;

 

And to mqx/source/include/fio.h

extern boolean _io_serial_int_write_force_polled_mode;

 

Then in mqx/source/psp/coldfire/int_unx.c, before first printf() add :

   _io_serial_int_write_force_polled_mode = TRUE; /* force polled UART mode (needed when called from ISR) */

and after last printf() :

   _io_serial_int_write_force_polled_mode = FALSE; /* no more force polled mode */

You can also force the output to be written to the default serial port instead of the current stdout (useful if the terminal of the task producing the exception is not a serial port; a telnet session for example); for this declare :

   pointer stdout_orig;
then before first printf :

   _io_serial_int_write_force_polled_mode = TRUE; /* force polled UART mode (needed when called from ISR) */
   stdout_orig = td_ptr->STDOUT_STREAM;
   td_ptr->STDOUT_STREAM = kernel_data->PROCESSOR_STDOUT; /* force printf output on default console */
and after last one :

   td_ptr->STDOUT_STREAM = stdout_orig; /* restore stdout */
   _io_serial_int_write_force_polled_mode = FALSE; /* no more force polled mode */

0 Kudos
Reply
1 Solution
909 Views
MarkP_
Contributor V

Hi,

Does this:  int_io_dev_ptr->DEV_PUTC(int_io_dev_ptr, c);

call the function: void _kuart_int_putc().

 

The function waits TX-register to be empty:

   while (!(sci_ptr->S1 & UART_S1_TDRE_MASK)) {
      /* Wait while buffer is full */
   } /* Endwhile */

Prevents/blocks other interrupts to be served during this time.

 

How about, if you increase a global variable in unexpected int routine and check and print

that variable in main task of you system.

~Mark

 

 

View solution in original post

0 Kudos
Reply
3 Replies
910 Views
MarkP_
Contributor V

Hi,

Does this:  int_io_dev_ptr->DEV_PUTC(int_io_dev_ptr, c);

call the function: void _kuart_int_putc().

 

The function waits TX-register to be empty:

   while (!(sci_ptr->S1 & UART_S1_TDRE_MASK)) {
      /* Wait while buffer is full */
   } /* Endwhile */

Prevents/blocks other interrupts to be served during this time.

 

How about, if you increase a global variable in unexpected int routine and check and print

that variable in main task of you system.

~Mark

 

 

0 Kudos
Reply
909 Views
trailman
Contributor V

Hi Mark,

 

You're right, the function called by int_io_dev_ptr->DEV_PUTC() polls the TX register before sending a character.

For MCF52259, this function is _mcf52xx_uart_serial_int_putc() defined in mqx/source/io/serial/int/serl_int_mcf52xx.c (this is set when calling _io_serial_int_install() in mqx/source/io/serial/int/serl_int.c to install the driver)

But this is not worse than doing this when using the polled UART driver. The purpose here is just to have the same functionality than with the polled UART driver.

 

OK, other interrupts are lost when printing characters from the ISR, but it's OK for me because the purpose is not to use prinf() in the ISRs used by the drivers (which would not be a good idea), but to display fatal exceptions (data access error, code corruption, ...) or unhandled ISRs (that should never occur).

On my system, I added a reset at the end of the int_unx.c to reset the board when such a problem occur, so I don't care about loosing interrupts. The more important to me is to know the task, the type of error, and the address in code at which the porblem occured.

0 Kudos
Reply
909 Views
trailman
Contributor V

There's probably a simplier solution without the extra variable  _io_serial_int_write_force_polled_mode, but I have not tested it yet.

Use

  if (_mqx_kernel_data->IN_ISR) {

instead of

  if (_io_serial_int_write_force_polled_mode) {

 

or cleaner but longer :

  KERNEL_DATA_STRUCT_PTR kernel_data;
  _GET_KERNEL_DATA(kernel_data);
  if (kernel_data->IN_ISR) {

0 Kudos
Reply