KEA64 - Low Level UART Setting up

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

KEA64 - Low Level UART Setting up

1,074 Views
curiosul
Contributor III

Hello!

I am trying to make a simple UART Echo application for a processor from family SKEAZN64. I simply want to get back any character send from a terminal via serial port.

My code consists of the following three files:

1. main.c

#include <stdint.h>
#include "SKEAZN642.h"
#include "UART.h"

/// Configure clock
void Clk_Init()
{
     ICS_C1 |= ICS_C1_IRCLKEN_MASK;                /* Enable the internal reference clock*/
     ICS_C3 = 0x50;                                    /* Reference clock frequency = 31.25 kHz*/
     while ( !(ICS_S & ICS_S_LOCK_MASK) );     /* Wait for PLL lock, now running at 40 MHz (1024*39.0625 kHz) */
     ICS_C2 |= ICS_C2_BDIV( 1 );                /*BDIV=2, Bus clock = 20 MHz*/
     //ICS_S |= ICS_S_LOCK_MASK;                     /* Clear Loss of lock sticky bit */ ????????
     //???
}

/// UART2 Callback Handler
void Uart_Interrupt(uint8_t data)
{
     // Print back received character
     Uart_SendChar( data );
}

int main(void)
{
     /// Clock initialization
     Clk_Init(); /* Configure clocks to run at 20 Mhz */

     /// UART2 Initialization
     UART_Init();                                   /*Initialize Uart2 at 9600 bauds */
     Uart_SetCallback( Uart_Interrupt );      /* Set the callback function that the UART driver will call when receiving a char */
     NVIC_EnableIRQ( UART2_IRQn );                /* Enable UART2 interrupt */

     // Send "WELCOME\r\n"
     Uart_SendChar( 0x57 );     // W
     Uart_SendChar( 0x45 );     // E
     Uart_SendChar( 0x4c );     // L
     Uart_SendChar( 0x43 );     // C
     Uart_SendChar( 0x4f );     // O
     Uart_SendChar( 0x4d );     // M
     Uart_SendChar( 0x45 );     // E
     Uart_SendChar( 0xD );     //\r
     Uart_SendChar( 0xA );     //\n

     for ( ;; )
     {
          static int i = 0;
          i++;
     }

     /* Never leave main */
     return 0;
}

2. UART.h

#ifndef UART_H_
#define UART_H_

#include <stdint.h>
#include "SKEAZN642.h"

/*******************************************************************************
* Types
********************************************************************************/
typedef void(*pt2Func)(void);            /* Pointer to Functions, void argument */
typedef void(*pt2FuncU8)(uint8_t);       /* Pointer to Functions, UINT8 argument */

void UART_Init(void); 
void Uart_SendChar(uint8_t send);
uint8_t Uart_GetChar(void);
void Uart_SetCallback(pt2FuncU8 ptr);

#endif /* UART_H_ */

3. UART.c

/// Global Variable
pt2FuncU8 Uart_Callback;

/// Local function prototype
void UART2_IRQHandler(void);

void UART_Init()
{
     SIM_SCGC |= SIM_SCGC_UART2_MASK;      /* Enable bus clock in UART2*/
     UART2_BDH = 0;                               /* One stop bit*/
     UART2_BDL = 128;                          /* Baud rate at 9600*/
     UART2_C1 = 0;                               /* No parity enable,8 bit format*/
     UART2_C2 |= UART_C2_TE_MASK;           /* Enable Transmitter*/
     UART2_C2 |= UART_C2_RE_MASK;           /* Enable Receiver*/
     UART2_C2 |= UART_C2_RIE_MASK;           /* Enable Receiver interrupts*/
}

void Uart_SetCallback(pt2FuncU8 ptr)
{
     Uart_Callback = ptr;
}

void Uart_SendChar(uint8_t send)
{
     while ( (UART2_S1 & UART_S1_TDRE_MASK) == 0 )
          ;                     /* Wait for transmit buffer to be empty*/

     (void)UART2_S1;      /* Read UART2_S1 register*/
     UART2_D = send;      /* Send data*/
}

uint8_t Uart_GetChar()
{
     uint8_t recieve;
     while ( ( UART2_S1 & UART_S1_RDRF_MASK) == 0 )
          ;                          /* Wait for received buffer to be full*/

     (void) UART2_S1;           /* Read UART2_S1 register*/
     recieve = UART2_D;           /* Read received data*/
     return recieve;
}

void UART2_IRQHandler()
{
     (void)UART2_S1; /* Clear reception flag mechanism*/
     Uart_Callback( Uart_GetChar() );
}

Now the code have some big problems:

1. Instead of sending initially "WELCOME\r\n" it just send "WEL_and_some_garbage". My guess is that it is not waiting for transmission buffer to be empty! But why not?

This is the loop which should block execution until another char can be send:

while (  (UART2_S1 & UART_S1_TDRE_MASK) == 0  );

But what's wrong with it?

2. The clock initialization

The function was extracted from official documentation AN4942:

void Clk_Init()
{
    ICS_C1 |= ICS_C1_IRCLKEN_MASK;             /* Enable the internal reference clock*/
    ICS_C3 = 0x50;                             /* Reference clock frequency = 31.25 kHz*/
    while ( !(ICS_S & ICS_S_LOCK_MASK) );    /* Wait for PLL lock, now running at 40 MHz (1024*39.0625 kHz) */
    ICS_C2 |= ICS_C2_BDIV( 1 );             /*BDIV=2, Bus clock = 20 MHz*/
    //ICS_S |= ICS_S_LOCK_MASK;                 /* Clear Loss of lock sticky bit */ ????????
    //???
}

However, there is an error on the last commented line: error: assignment of read-only member 'S'

Have no clue why so I just commented that line!

3. The callback function is not called when a character is send from UART0.

PS: The UART2 port works fine with processor Expert.

PS2: Most of the code is from: https://www.nxp.com/docs/en/application-note/AN4942.pdf 

I also have attached the project archive in case you may want to give a try!

0 Kudos
1 Reply

616 Views
mjbcswitzerland
Specialist V

Hi Alex

1)
while (  (UART2_S1 & UART_S1_TDRE_MASK) == 0  );
looks OK so there is probably a different reason for it not operating as expected.

Note that if you use Tx interrupts this method is very inefficient - you should instead use a Tx buffer and send each subsequent character in the interrupt so that your code doesn't block.

2)
Check how ICS_S is defined in the header file - if it is a const register it won't let you write to it, which would not be exactly correct because one can write a '1' to clear the loss bit.
Also check that you are clearing the correct bit since ICS_S_LOCK_MASK looks incorrect to me - I think you will find you need to write a bit called LOLS instead.
Not doing this will generally not be a problem because it is unlikely that the flag will be set. Also, if it remains set it doesn't make any difference if you are not checking it elsewhere.

3)
I don't see that the UART Tx interrupt is enabled anywhere and so it may be normal that the interrupt callback is thus never called.

See links below for a complete Open Source solution for KEA64 including buffered UART method and (approx.) real-time simulation of KEA64 in Visual Studio.

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html
Kinetis KEA64:
- http://www.utasker.com/kinetis/FRDM-KEAZ64Q64.html
- http://www.utasker.com/kinetis/TRK-KEA64.html
S32 Design Studio: http://www.utasker.com/kinetis/compilers.html#S32
UART: http://www.utasker.com/docs/uTasker/uTaskerUART.PDF
UART videos:
- https://youtu.be/OrqSn9x7N1E
- https://youtu.be/GaoWE-tMRq4
- https://youtu.be/89sZ4nW-mgw

Free Open Source solution: https://github.com/uTasker/uTasker-Kinetis
Working project in 15 minutes video: https://youtu.be/K8ScSgpgQ6M

For better, faster, cheaper product developments consider the uTasker developer's version, professional Kinetis support, one-on-one training and complete fast-track project solutions to set you apart from the herd : http://www.utasker.com/support.html

0 Kudos