AnsweredAssumed Answered

Help Setting Up UART0 Intterupt For MCU to PC Comm?

Question asked by Miguel Amaro on Nov 23, 2019
Latest reply on Nov 27, 2019 by Robin_Shen

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;
}

Outcomes