Need help with K10 UART Interrupt

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

Need help with K10 UART Interrupt

7,380 Views
ignisuti
Contributor IV

I've done the following:

 

UART_C2_REG[ RIE ] = 1  //Enable interrupt when S1[RDRF] is set.

UART_C2_REG[ TE ] = 1//Enable Transmitter

UART_C2_REG[ RE ] = 1 //Enable Receiver

 

UART_C5_REG[ RDMAS ] = 0 //Configure for interrupt, not DMA.

 

UART_RWFIFO_REG[ UART_RWFIFO_RXWATER ] = 1 //Set interrupt to occur after 1 byte is present in the buffer.

 

I'll spare you the rest of my configuration, but please know I have UART0 working with 100MHz clock and configured with 115200 baud rate.

 

I've also added the name of my interrupt function (UART__INTERRUPT__RX) at IRQ 45 (address 0x0000_00F4) of the Vector Table.

 

However, function UART__INTERRUPT__RX() is never entered when I send keypresses via HyperTerminal. I can see the  data I transmit to HypterTerminal.

 

I thought I had everything correctly setup. What else do I need to configure to make this work?


0 Kudos
Reply
16 Replies

2,511 Views
gogreen
Contributor I

Hi ignisuti

 

I'm a novice programmer of UART for Kinetis(K10).

Can you please provide an example code of the uart functions including interrupt (along with parity bit enabled)?

I would be grateful to you for your support.

 

0 Kudos
Reply

2,511 Views
ignisuti
Contributor IV

 

gogreen,

You'll have to study and understand each of these sections (specifically the meaning of each control register). But, this should give you a good start. After you understand the purpose of each register in the initialize function, you'll quickly understand how to add the parity you need.

 

I've left out the declaration of few global variables that this code depends on like: UART__buffer, UART__byte_cnt, CPU__clk_hz__bus, CPU__clk_hz__core

But, I figured this stuff will be easy to figure out and add after you understand what is going on with all this code.

 

Anyone else reading this, please feel free to provide suggestions for improvements.

 

/*--------------------------------------------------------------------                         ENUMERATIONS & TYPES--------------------------------------------------------------------*/    typedef enum UART_CHANNELS    {    UART_CHANNEL__A  = 0,    UART_CHANNEL__B = 1,    UART_CHANNEL__C  = 2,    UART_CHANNEL__D   = 3,     UART_CHANNEL__E = 4,         UART_CHANNEL__CNT            }UART__channel_t;    /*--------------------------------------------------------------------                           MEMORY CONSTANTS--------------------------------------------------------------------*//* Table of pointers to SPI register addresses. */static UART_MemMapPtr const UART__base_ptr_tbl[ UART_CHANNEL__CNT ] =    {    UART0_BASE_PTR, /* UART 0 - UART_CHANNEL__A  */    UART1_BASE_PTR, /* UART 1 - UART_CHANNEL__B  */    UART2_BASE_PTR, /* UART 2 - UART_CHANNEL__C  */    UART3_BASE_PTR, /* UART 3 - UART_CHANNEL__D  */    UART4_BASE_PTR  /* UART 4 - UART_CHANNEL__E  */        };

 

 

void UART__initialize  (     UART__channel_t  channel_number,    u32      baud_rate  )    {        /* Enable appropriate UART clock gate. */       enable_clock_gate( channel_number );                                          /* Turn the Transmitter and Receiver off temporarily while configuring the UART. */    disable_uart( channel_number );             UART_C2_REG( UART__base_ptr_tbl[channel_number] ) = UART_C2_RIE_MASK;    UART_C1_REG( UART__base_ptr_tbl[channel_number] ) = 0;    UART_C5_REG( UART__base_ptr_tbl[channel_number] ) = 0;        UART_RWFIFO_REG( UART__base_ptr_tbl[channel_number] ) = UART_RWFIFO_RXWATER( 1 );     UART_C3_REG( UART__base_ptr_tbl[channel_number] ) |= UART_C3_TXDIR_MASK;         set_baud_rate( channel_number, baud_rate );    enable_uart( channel_number );        } /* UART__initialize() */

 

void UART__write  (  UART__channel_t  channel_number,   char     *data  )    {    /* Local Variables. */    u32 byte_idx;    u32 str_len;    /* Get string length. */    str_len = strlen( data );        /* Loop through and send each byte. */    for( byte_idx = 0; byte_idx < str_len; byte_idx++ ) { /* Wait until current transmission is complete. */ while(!(UART_S1_REG( UART__base_ptr_tbl[ channel_number ] ) & UART_S1_TC_MASK));      /* Send the current byte. */ UART_D_REG( UART__base_ptr_tbl[ channel_number ] ) = (u8)data[ byte_idx ]; }           } /* UART__write() */

 

static void disable_clock_gate  (  UART__channel_t  channel_number  )    {            /* Determine correct parameters for specified UART module. */       switch( channel_number ) { case UART_CHANNEL__B:  //UART 1     SIM_SCGC4 &= ~SIM_SCGC4_UART1_MASK; //Disable Clock Gating.     break;      case UART_CHANNEL__C:   //UART 2     SIM_SCGC4 &= ~SIM_SCGC4_UART2_MASK; //Disable Clock Gating.     break;      case UART_CHANNEL__D:  //UART 3     SIM_SCGC4 &= ~SIM_SCGC4_UART3_MASK; //Disable Clock Gating.     break;      case UART_CHANNEL__E:  //UART 4     SIM_SCGC1 &= ~SIM_SCGC1_UART4_MASK; //Disable Clock Gating.     break;           case UART_CHANNEL__A:  //UART 0 default:     SIM_SCGC4 &= ~SIM_SCGC4_UART0_MASK; //Disable Clock Gating.     break; }            } /* disable_clock_gate() */static void disable_uart  (  UART__channel_t  channel_number  )    {            /* Wait until current transmission is complete. */    while(!(UART_S1_REG( UART__base_ptr_tbl[ channel_number ] ) & UART_S1_TC_MASK));           /* Disable receiver and transmitter */    UART_C2_REG( UART__base_ptr_tbl[channel_number] ) &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK );                                } /* disable_uart() */static void enable_clock_gate  (  UART__channel_t  channel_number  )    {            /* Determine correct parameters for specified UART module. */       switch( channel_number ) { case UART_CHANNEL__B:  //UART 1     SIM_SCGC4 |= SIM_SCGC4_UART1_MASK;  //Enable Clock Gating.     break;      case UART_CHANNEL__C:   //UART 2     SIM_SCGC4 |= SIM_SCGC4_UART2_MASK;  //Enable Clock Gating.     break;      case UART_CHANNEL__D:  //UART 3      SIM_SCGC4 |= SIM_SCGC4_UART3_MASK;  //Enable Clock Gating.     break;      case UART_CHANNEL__E:  //UART 4     SIM_SCGC1 |= SIM_SCGC1_UART4_MASK;  //Enable Clock Gating.     break;           case UART_CHANNEL__A:  //UART 0 default:     SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;  //Enable Clock Gating.     break; }            } /* enable_clock_gate() */static void enable_uart  (  UART__channel_t  channel_number  )    {               /* Enable receiver and transmitter */    UART_C2_REG( UART__base_ptr_tbl[channel_number] ) |= (UART_C2_TE_MASK | UART_C2_RE_MASK );        } /* enable_uart() */static void set_baud_rate  (  UART__channel_t  channel_number,    u32      baud_rate  )    {    /* Local Variables. */    u16  sbr;     u16  brfa;    u32  clk_hz;        /* Determine appropriate clock for use with baud rate calculations. */    if ( (channel_number == 0)       || (channel_number == 1) ) { /* UART0 and UART1 are clocked from the core clock. */ clk_hz = CPU__clk_hz__core; }    else {/* All other UARTs are clocked from the peripheral bus clock. */ clk_hz = CPU__clk_hz__bus;        }        /* Calculate baud settings      * Ex:      * Using a 100MHz clock with a desired baud rate of 115200:      * These formulas provide the following: sbr=54, brfa=8.     * These values result in a baud rate of 115207.4 ==> 100,000,000Hz / (16 * (54 + (8 / 32)))     * This provides us a very low error of 0.0064% ==> ((115207.4 / 115200) - 1) * 100. */    sbr = (u16)(clk_hz/(baud_rate * 16));    brfa = (((clk_hz*32)/(baud_rate * 16)) - (sbr * 32));      UART_BDH_REG( UART__base_ptr_tbl[channel_number] ) = UART_BDH_SBR(((sbr & 0x1F00) >> 8));       UART_BDL_REG( UART__base_ptr_tbl[channel_number] ) = (u8)(sbr & UART_BDL_SBR_MASK);           UART_C4_REG( UART__base_ptr_tbl[channel_number] ) = UART_C4_BRFA(brfa);        } /* set_baud_rate() */

 

void UART0__INTERRUPT__RX  (  void  )    {    /* Local Variables. */    bool rdrf_bit;    u8 new_byte;        /* Local Defines. */    #define UART_CH  ( 0 )   /* UART 0  */    /*    if( UART_RCFIFO_REG( UART__base_ptr_tbl[ UART_CH ] ) > 1 ) { new_byte = 1; }     */        /* Read S1[RDRF] (Receive Data Register Full Flag).      * This is required to clear the flag so the interrupt will not re-trigger.      * Note, the flag will not be cleared until after data register read. */    rdrf_bit = BIT_READ( UART_S1_REG( UART__base_ptr_tbl[ UART_CH ] ), UART_S1_RDRF_SHIFT );     /* Read data from UART buffer. */    new_byte = UART_D_REG( UART__base_ptr_tbl[ UART_CH ] );        /* Record data into appropriate buffer. */    UART__buffer[ UART_CH ][ UART__byte_cnt[ UART_CH ]++ ] = new_byte;                /* Wait for S1[RDRF] bit to indicate RX buffer is empty.     while( rdrf_bit == TRUE ) { rdrf_bit = BIT_READ( UART_S1_REG( UART__base_ptr_tbl[ UART_CH ] ), UART_S1_RDRF_SHIFT ); }             */        /* Check if data is coming in faster than it's being handled. 50% arbitrarily chosen. */    if( UART__byte_cnt[ UART_CH ] >= UART__buffer_size / 2 ) {    /* This code should never process, but write your own code here to handle this error incase it does. */           /* Clear the buffer as an attempt to recover. */ UART__flush_buffer( UART_CH );    }     } /* UART0__INTERRUPT__RX() */

 

0 Kudos
Reply

2,511 Views
gogreen
Contributor I

Thanks ignisuti.

 

Can you please send the function definitions and variable definitions declared in interrupt function?

Also, please send the main() for this uart driver.

0 Kudos
Reply

2,511 Views
ignisuti
Contributor IV

I really hate when people do this to me, but I think it's a good idea here to make you work just a little. 

I've already handed you some pretty well polished functions. 

 

If you take the time to study and understand what's going on in them, I think the function calls and global variables will become apparent to you.

 

Good luck!

0 Kudos
Reply

2,511 Views
marcotiberio
Contributor I

Dear Joe,

I saw this post and I need to ask you a thing because me too I have a problem with UART on the kinetis FRDM-K64F board and I' m going crazy.

Following there is my code. I am not able to write and to read the D data regisetr, as if it was write protected.

I saw many Freescale example code and all are the same as mine.

Where is the bug?

I thank in advance for all the help that you want to give me.

/******************     uart.c     ***************************/

void UART_Init ( UART_Type *pUART ){

  uint16_t u16Sbr, u16Brfa;

  uint8_t u8Temp;

  uint32_t u32SysClk = 120000;   // system clock in KHz

  uint32_t u32Baud = UART_BAUDRATE;

/* Enable the clock to the selected PORT */

  SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK;

  /* Set the pins (those that are directly connected to OpenSDA) multiplexer to UART RX/TX mode */

  PORTB->PCR[16] = PORT_PCR_MUX( 3 );

  PORTB->PCR[17] = PORT_PCR_MUX( 3 );

  /* Enable the clock to the selected UART */

  SIM->SCGC4 |= SIM_SCGC4_UART1_MASK;

  /* Make sure that the transmitter and receiver are disabled while we

  * change settings.

  */

  pUART->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK );

  /* Configure the UART for 8-bit mode, no parity */

  pUART->C1 = 0;

  /* Calculate baud settings */

  //u16Sbr = (((u32SysClk)>>4) + (u32Baud>>1))/u32Baud;

  u16Sbr = (uint16_t)((((u32SysClk*1000)>>4))/u32Baud);

  /* Save off the current value of the UARTx_BDH except for the SBR field */

  u8Temp = pUART->BDH & ~(UART_BDH_SBR_MASK);

  pUART->BDH = u8Temp |  UART_BDH_SBR(((u16Sbr & 0x1F00) >> 8));

  pUART->BDL = (uint8_t)(u16Sbr & UART_BDL_SBR_MASK);

  /* Determine if a fractional divider is needed to get closer to the baud rate */

  u16Brfa = (((u32SysClk*32000)/(u32Baud * 16)) - (u16Sbr * 32));

  /* Save off the current value of the UARTx_C4 register except for the BRFA field */

  u8Temp = pUART->C4 & ~(UART_C4_BRFA(0x1F));

  pUART->C4 = u8Temp |  UART_C4_BRFA(u16Brfa);

  /* Enable receiver and transmitter */

  pUART->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK );

}

uint8_t UART_GetChar(UART_Type *pUART)

{

    /* Wait until character has been received */

    while (!(pUART->S1 & UART_S1_RDRF_MASK));

    /* Return the 8-bit data from the receiver */

    return pUART->D;

}

void UART_PutChar(UART_Type *pUART, uint8_t u8Char)

{

  /* Wait until space is available in the FIFO */

    while (!(pUART->S1 & UART_S1_TDRE_MASK));

    /* Send the character */

    pUART->D = (uint8_t)u8Char;

}

/******************     main.c     ***************************/

int main()

{

    //init_hardware();

   

  uint8_t buffer[128] = "Hello World!";

  int i = 0;

  UART_Init(UART1);

  for(;;)

    {

    while ( buffer[i] != '\0' )

    {

    UART_PutChar( UART1, buffer[i++] );

    }

    }

}

0 Kudos
Reply

2,511 Views
mjbcswitzerland
Specialist V

Hi Marco

In order to be able to test your code on the FRDM-K64F board please do one of the following:

- Make a zip file from the complete workspace (I understand you use KDS) so that the complete code can be built, loaded and the reason investigated

- Send a binary of the code being loaded to the board (so that it can be loaded with the mbed loader) along with the generated map file( so that the locations in code can be approximately identified) so that it can be investigated in the disassembly.

Once you have posted the file(s) I should be able to explain what is causing the problem.

Regards

Mark

0 Kudos
Reply

2,511 Views
marcotiberio
Contributor I

Dear Mark,

yes, I have forgot it, I am using KDS.

I am attaching the .zip file of my project.

Thank for all the support that you are giving to me.

Best regards.

Marco

On Mon, 07 Jul 2014 10:12:09 -0700, Mark Butcher

0 Kudos
Reply

2,511 Views
mjbcswitzerland
Specialist V

Hi Marco

I loaded your code but found no problem with the UART data register access - possibly you were writing the register with the debugger and expecting to see the value in it that you wrote; in this case remember that the UART data register is written to send data out and "reads" the last reception; you would only see the value written if there were a loopback and so it would be quite normal to not see the data written to it (usually 0xff is read if idle line).

In the code I found what you are configuring PB16 and PB17 for UART0 pins but then using UART1.

If yopu change UART1 to UART0, and also adjust the peripheral power up in the UART initialisation from

SIM->SCGC4 |= SIM_SCGC4_UART1_MASK;

to

SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;

it then sends the "Hello World!" message out and this is visible on the virtual COM port.

The initialisation code sets115200Baud but its actual speed is 19200Baud. This is probably because the system clock setting in code doesn't match the real system clock setting (I think the code expects 120MHz but it is probably running at 20MHz instead).

Regards

Mark

0 Kudos
Reply

2,511 Views
marcotiberio
Contributor I

Dear Mark,

Yeah, it works!!!!

The main problem was just that the correct one was the UART0!

But, to choose the correct UART, those directly connected to the OpenSDA, I

have seen on the document that I attached to you. In this document,

therefore, there is a mistake because it is written that is the UART1 those

connected to the OpenSDA through the related pins of PORTB...

Instead, the board's reference manual is correct, PTB16 and PTB17 are UART0

RX/TX respectively.

Again, you obviously are right! With 120000 as SysClk the baud rate is

19200 instead of the desired 115200, whereas, with SysClk of about 20 MHz

the baudrate setting of 115200 is satisfied!

Thank you so much for your precious help and for the availability that you

have given me.

I hope that one day I may help you.

You are the best.

Best regards.

Marco

On Mon, 07 Jul 2014 15:17:10 -0700, Mark Butcher

0 Kudos
Reply

2,511 Views
mjbcswitzerland
Specialist V

Marco

Yes, I see that that there is a mistake in the user's manual to the board - it really does say that UART1 is used.

However you always need to be cautious with user manuals - only believe the circuit diagram and not that which someone has written about it. If possible work directly with the circuit diagram and only use the user's manual as "additional general information" if needed....

Regards

Mark

0 Kudos
Reply

2,511 Views
mjbcswitzerland
Specialist V

Hi

 

Is the port used by the UART's pins powered up and are the individual pins configured for UART multiplexed mode?

 

Regards

 

Mark

 

0 Kudos
Reply

2,511 Views
ignisuti
Contributor IV

I have configured the RX and TX lines as shown below:

 

PORTD_PCR6 = PORT_PCR_MUX(3); //Configure as UART0 RX
PORTD_PCR7 = PORT_PCR_MUX(3); //Configure as UART0 TX

 

Mark, what do you mean by powering-up the port? Can you provide an example?

0 Kudos
Reply

2,511 Views
mjbcswitzerland
Specialist V

Hi

Just as you need to power up the UART before writing its registers

eg. SIM_SCGC4 |= SIM_SCGC4_UART0;

each port needs to be powered up before its pins can be used.

eg. SIM_SCGC5 |= SIM_SCGC5_PORTD;

 

 

In the uTasker project these details are handled by macros so it looks like this for your case with UART0 on port D pins, whereby the macros also ensure that each used port is automatically enabled:

 

 

POWER_UP(4, SIM_SCGC4_UART0);                 // power up the UART_CONFIG_PERIPHERAL(D, 7, PD_7_UART0_TX);  // UART0_TX on PD7 (alt. function 3)_CONFIG_PERIPHERAL(D, 6, PD_6_UART0_RX);  // UART0_RX on PD6 (alt. function 3)

 Some additional details can be found in the GPIO and UART sections of

http://www.utasker.com/docs/KINETIS/uTaskerV1.4_Kinetis_demo.pdf

 

 

Regards

 

Mark

 

 

0 Kudos
Reply

2,511 Views
ignisuti
Contributor IV

Mark, yes, I've already got all the port clock gates enabled.

 

I'm pulling my hair out with this one. I just need S1[RDRF] to trigger. I've put a scope on the MCU RX line and verified data is coming into the MCU.

 

What conditions must be present for S1[RDRF] to trigger? I'm sure it's probably something as simple as 1 bit I didn't set somewhere.

0 Kudos
Reply

2,511 Views
ndavies
Contributor V

I see you enabled the interrupt in the UART registers, Did you also enable the interrupt in the NVIC. This is needed to pass the interrupt on to the CPU?

0 Kudos
Reply

2,511 Views
ignisuti
Contributor IV

That's the part I was missing! It's working now.

 

Thank you!!!

0 Kudos
Reply