Board: KL25Z
I'm having trouble getting this example from my arm book to work. I'm supposed to setup UART0 and GPIOA, pins 1 and 2 to talk with OpenSDA which can communicate with my PC via Teraterm.
All I know is that in the Init_UART0() function, after Port A pins 1 and 2 are set(lines 84 & 85) to Tx and Rx the UART0_IRQHandler() immediately gets called and then the program gets stuck on the if statement that checks the Receive Data Register(line 158) like it's an infinite loop. I haven't sent any characters from my PC...
Any idea why this is happening or tips on how I can fix it?
//================== Includes ======================
#include "MKL25Z4.h" // Device header
#include <stdio.h>
//=================== Defines ======================
#define UART_OVERSAMPLE_RATE (16)
#define SYS_CLOCK (48E6)
#define Q_MAX_SIZE (256)
//================= Structures ======================
typedef struct {
uint8_t Data[Q_MAX_SIZE];
unsigned int Head; //Index of the oldest data element
unsigned int Tail; //Index of the next free space
unsigned int Size; //Number of elements in use
} volatile Q_T;
//================== Globals ==========================
Q_T TxQ;
Q_T RxQ;
//================ Prototypes ===========================
void Init_UART0(uint32_t);
int Q_Enqueue(Q_T*, uint8_t);
uint8_t Q_Dequeue(Q_T* );
void Q_Init (Q_T* );
int Q_Empty (Q_T* );
int Q_Full (Q_T* );
int Q_Size (Q_T* );
//================== Entry Point ===============================
int main(){
uint8_t buffer[80], myChar, * buffPtr;
Init_UART0(115200);
Q_Enqueue(&TxQ, 'a');
while(1){
//blocking recieve
while(Q_Size(&RxQ) == 0); //Loops until there data in the queue
myChar = Q_Dequeue(&RxQ);
//Blocking transmit
sprintf((char *)buffer, "You pressed %c\n\r",myChar);
//enqueue string
buffPtr = buffer;
while(*buffPtr != '\0'){
//Copy characters up to null terminator
while(Q_Full(&TxQ)); //Wait for space to open up
Q_Enqueue(&TxQ, *buffPtr);
buffPtr++;
}
//Start transmitter if it isn's already running
if(!(UART0->C2 & UART0_C2_TIE_MASK)){
UART0->C2 |= UART0_C2_TIE(1);
}
}
}
//=================== Function Definitions =========================
// *********************************************
// Initiate and Setup UART and interrupts *
// *********************************************
void Init_UART0(uint32_t baudRate){
uint16_t sbr;
//Enable clock gating for UART0 and PortA
SIM->SCGC4 |= SIM_SCGC4_UART0_MASK;
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
//Make sure transmitter and receciver are disabled before init
UART0->C2 &= ~UART0_C2_TE_MASK & ~UART0_C2_RE_MASK;
//Set UART cloack to 48 MHz clock
SIM->SOPT2 |= SIM_SOPT2_UART0SRC(1); //What is this source MCG?
SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
//Set pins to UART0 Rx and Tx
PORTA->PCR[1] = PORT_PCR_ISF_MASK | PORT_PCR_MUX(2); //Rx
PORTA->PCR[2] = PORT_PCR_ISF_MASK | PORT_PCR_MUX(2); //Tx
//================ Info on the registers can be found on pg.228 - 230 =====================
/*Registers
*UARTx_C1 - Control register 1
*UARTx_C2 - Control register 2
*UARTx_S1 - Status register 1
*
*Acronyms
*PF - Parity Error Flag
*FE - Framing Error Flag
*NF - Noise Detected Flag
*TC - Transmition Complete Flag
*OR - Rx buffer data not read before new data was recieved
*TDRE - buffer has room for another character
*RDRF - theres data to read from the recieve buffer
*IDLE - data line is idle
*TIE - if(1) interrupt when transmit data register is empty
*RIE - if(1) interrupt when recieve data register is full
*MSBF - if(1) Most Significent Bits is sent first
*RXINV - if(1) inverts recieved data
*ORIE, NEIE, FEIE, PEIE - interrupt when corresponding flag is set
*/
//Set baud rate and oversampling ratio
sbr = (uint16_t)((SYS_CLOCK)/(baudRate * UART_OVERSAMPLE_RATE));
UART0->BDH &= ~UART0_BDH_SBR_MASK;
UART0->BDH |= UART0_BDH_SBR(sbr>>8);
UART0->BDL = UART0_BDL_SBR(sbr );
UART0->C4 |= UART0_C4_OSR(UART_OVERSAMPLE_RATE - 1);
//Disable interrupts for RX active edge and LIN break detect, select one stop bit
UART0->BDH |= UART0_BDH_RXEDGIE(0) | UART0_BDH_SBNS(0) | UART0_BDH_LBKDIE(0);
//Don't enable loopback mode, use 8 data bit mode, don't use parity
UART0->C1 |= UART0_C1_LOOPS(0) | UART0_C1_M(0) |UART_C1_PE(0);
//Don't invert transmit data, do enable interrupts for errors
UART0->C3 |= UART_C3_TXINV(0) | UART0_C3_ORIE(1) | UART0_C3_NEIE(1)
| UART0_C3_FEIE(1) | UART0_C3_PEIE(1);
//Clear error flags
UART0->S1 = UART0_S1_OR(1) | UART0_S1_NF(1) | UART0_S1_FE(1) | UART0_S1_PF(1);
//Send LSB first, do not invert received data
UART0->S2 |= UART0_S2_MSBF(0) | UART0_S2_RXINV(0);
Q_Init(&TxQ);
Q_Init(&RxQ);
NVIC_SetPriority (UART0_IRQn, 2); //0, 1, 2, or 3
NVIC_ClearPendingIRQ(UART0_IRQn );
NVIC_EnableIRQ (UART0_IRQn );
UART0->C2 |= UART0_C2_RIE(1);
//Enable
UART0->C2 |= UART0_C2_TE(1) | UART_C2_RE(1);
}
//*********************************************
// UART0 Interrupt Request Handler *
//*********************************************
void UART0_IRQHandler(void){
uint8_t myChar;
if(UART0->S1 & (UART_S1_OR_MASK | UART_S1_NF_MASK |
UART_S1_FE_MASK | UART_S1_PF_MASK)){
//clear the error flags
UART0->S1 |= UART0_S1_OR_MASK | UART0_S1_NF_MASK |
UART0_S1_FE_MASK | UART0_S1_PF_MASK;
//Read the data register to clear RDRF
myChar = UART0->D;
}
if(UART0->S1 & UART0_S1_RDRF_MASK){
//Recieved a character
myChar = UART0->D;
if(!Q_Full(&RxQ)){
Q_Enqueue(&RxQ, myChar);
}
else{
//error - queue full
//discard character
}
}
if((UART0->C2 & UART0_C2_TIE_MASK) &&
(UART0->S1 & UART0_S1_TDRE_MASK)){
//Can sen another character
if(!Q_Empty(&TxQ)){
UART0->D = Q_Dequeue(&TxQ);
}
else{
//queue is empty so disable transmitter interrupt
UART0->C2 &= ~UART0_C2_TIE_MASK;
}
}
}
//******************************************************************
// Initializes values in Transmit and Receive Queue Structures *
//******************************************************************
void Q_Init(Q_T* queue){
unsigned int i;
for(i = 0; i < Q_MAX_SIZE; i++)
queue->Data[i] = 0;
queue->Head = 0;
queue->Tail = 0;
queue->Size = 0;
}
//*********************************************************
// Returns State and Info of a Queue Strucuture *
//*********************************************************
int Q_Empty (Q_T* queue){
return queue->Size == 0;
}
int Q_Full (Q_T* queue){
return queue->Size == Q_MAX_SIZE;
}
int Q_Size (Q_T* queue){
return queue->Size;
}
//*****************************************************************
// Inserts data into the Queue and updates the Queue's members *
//*****************************************************************
int Q_Enqueue(Q_T* queue, uint8_t data){
uint32_t masking_state;
//If queue is full, don't overwrite data, but do return an error code
if(!Q_Full(queue)){
queue->Data[queue->Tail++] = data;
queue->Tail%= Q_MAX_SIZE;
//Protect queue->Size++ operation from premption
//Save current masking state
masking_state = __get_PRIMASK();
//Disable interrupts
__disable_irq();
//Update variable
queue->Size++;
//Restore interrupt masking state
__set_PRIMASK(masking_state);
return 1; //Success
}else
return 0; //Failure
}
//******************************************************************
// Extracts data from the Queue and updates the Queue's members *
//******************************************************************
uint8_t Q_Dequeue(Q_T* queue){
uint8_t masking_state;
uint8_t transmition = 0;
if(!Q_Empty(queue)){
transmition = queue->Data[queue->Head];
queue->Data[queue->Head++] = '_'; //Empty unused entries for debugging
queue->Head %= Q_MAX_SIZE;
//Protect queue->Size-- operation from preemption
//Save current masking state
masking_state = __get_PRIMASK();
//Disable interrupts
__disable_irq();
//Update variable
queue->Size;
//Restore interrupt masking state
__set_PRIMASK(masking_state);
}
return transmition;
}
Hi Miguel,
Please download the latest MCUXpresso SDK of FRDM-KL25Z and refer the uart_interrupt example.
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Haha Thanks. Wait, what was my question again?
Have you check the waveform on UART pins by using oscilloscope?
I am not able to gets stuck on line 158.
Are you using FRDM-KL25Z board?
Best Regards,
Robin