UART0 ISR for a single Received Byte

Status
Not open for further replies.

HGPAust

Member
I am currently working on a project that involves sending an IrDA signal to a remote sensor to initiate data collection. I have used a hardware interrupt to initiate the encoding and transmission of a code to the remote sensor. As part of development the transmitted code is sent directly back into the receive UART0 RX pin. I then enabled the IRQ_UART0_STATUS and enabled the UART_S1_RDRF Flag. The attached code includes the code and a function uart_Init(int UartCh, int pulse_Width), which changes the registers to enable the IrDA encode and decoding function and the configuration to enable the Control Registers for the interrupts. The code works but is not an elegant solution.

"
Code:
" 
[CODE]/*This is a test sketch to uses both Pin and Flag initiated interrupts to transmit and receive IrDA encoded signals. The sketch has a function uart-init that configures both the IR enabling registers as well as the interrupt and flag enabling registers.*/

unsigned long baud = 19200;

int led = 13;              //Pin 21
int buttonInt = 20;        //Pin 20
int PinTX1 = 5;
int PinRX1 = 21;
int rd, wr;
byte buffer[2];

//Establishes a interrupt stable boolean variable
volatile boolean ledOn = false;
volatile int Count = 0;
volatile int i, j;
volatile byte tempArray[4];
volatile uint32_t TEMP = 1;
volatile uint32_t TEMP2;
volatile int Flag;

void setup(){

  Serial.begin(baud);
  Serial1.begin(baud); // USB, communication to PC or Mac
  //HWSERIAL.begin(baud);  // communication to hardware serial

  //Configure pin modes.
  pinMode(led, OUTPUT);
  pinMode(buttonInt,INPUT);
  pinMode(PinTX1,OUTPUT);
  pinMode(PinRX1,INPUT);

  /*Implement function “uart_init” , this function sets up the required registers for IrDA transfer 
  and receive as well as the registers to configure the required flags.*/
  uart_init (0,4);//
  /*The first variable determines the UART channel and the second determines the 
  Pulse width i.e. 1 = 1/32 pulse width, 2 = 1/16 pulse width, 3 = 3/16 pulse width and
  4 = ¼ pulse width.*/

  //Configure the Interrupts.
  NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);// this enables the IRQ for the UART0 IRQ;
  attachInterrupt(buttonInt, buttonPressed, RISING);
  attachInterruptVector(IRQ_UART0_STATUS, myuart0_status_isr);
  
  //print ready Flag.
  Serial.println("UART0 Registers are set!");
}

/*The hardware Interrupt function. Sends four the bytes (one Dataword) to the UART0_D register 
 and increments HGP by one integer. At least one Dataword has to be sent the UART_D register 
 to initiate the Receive Data Register Full Flag (RDRF).
*/
void buttonPressed(){
  cli();
    int i;
    for(i=0;i<4; i++){
      UART0_D = ((TEMP>>(i*8))&0xFF);
    }
  
    Serial.print("UART0_D transmit value is ");
    Serial.println(TEMP);
    TEMP = TEMP + 1;
    UART0_S1 = 0;
  sei();
}
// The flag initiated interrupt.
void myuart0_status_isr(void) { 
  //Create a variable regStatus to capture the status of the UART0_S1 register.
  uint8_t regStatus;
  regStatus = UART0_S1;

  if (regStatus & UART_S1_RDRF) {// is true if the RDRF flag is a '1' ie the UART_S1 is 0x20 UART_S1_RDRF.
    //digitalWrite(led, LOW);   // Flag checks that the flag gets to the logic statement. 
    cli();
      Serial.println("Flag 01 - RDRF flag triggered");
      TEMP2 = UART0_D;   
      UART0_CFIFO = UART_CFIFO_RXFLUSH;
    sei();
    }
  Serial.print("UART0_D received value is ");
  Serial.println(TEMP2);
  Serial.println();
}

void loop()
{  
  //Do nothing in this loop!
}

void uart_init (int UartCh, int pulse_Width)
{
  /* Enable the clock to the selected UART */
  
      byte UART_IR_Mask1, UART_IR_Mask0;
      /*Enable the clock to the selected UART */
      long UART_SCGC4_Mask1 = 0xFFFFFBFF;
      long UART_SCGC4_Mask0 = 0x00000400;
      /* Disable Transmitter and Receiver before changing UART Registers*/
      UART0_C2 = 0;
      //Configure the UARTx_C1 Register
      byte UART_C1_Mask1 = 0xFF;
      byte UART_C1_Mask0 = 0x00;
      //Configure the UARTx_C2 Register
      byte UART_C2_Mask1 = 0xD3;
      byte UART_C2_Mask0 = 0x2C;
      //Configure the UARTx_IR register
      if (pulse_Width == 1)
      {
        //Load Masks for a narrow pulse of 1/32 pulse width.
        UART_IR_Mask1 = 0xF9;
        UART_IR_Mask0 = 0x06;
      }
      else if (pulse_Width == 2)
      {
        //Load Masks for a narrow pulse of 1/16 pulse width.
        UART_IR_Mask1 = 0xFA;
        UART_IR_Mask0 = 0x05;
      }
      else if (pulse_Width == 3)//Load Masks for a narrow pulse of 3/16 pulse width.
      {
        UART_IR_Mask1 = 0xFB;
        UART_IR_Mask0 = 0x04;
      }
      else //Load Masks for a narrow pulse of 1/4 pulse width.
      {
        UART_IR_Mask1 = 0xF8;
        UART_IR_Mask0 = 0x07;
      }
      //Configure Pin control Register for PTA1 
      long PORTD_PCR7_Mask1 = 
      long PORTD_PCR7_Mask0 = 
      //Configure Pin control Register for PTA2 
      long PORTD_PCR6_Mask1 = 0xFFFFF8FF;
      long PORTD_PCR6_Mask0 = 0x00000300;
      // Configure the UART_PFIFO
      byte UART_PFIFO_Mask1 = 0xFF;
      byte UART_PFIFO_Mask0 = 0x00;
      /* Enable the clock to UART0 */
      SIM_SCGC4 = (SIM_SCGC4 & UART_SCGC4_Mask1) | UART_SCGC4_Mask0;
      /* Configure UART_C1 Register*/
      UART0_C1 = (UART0_C1 & UART_C1_Mask1) | UART_C1_Mask0;
      /* Configure UART_IR Register*/
      UART0_IR = (UART0_IR & UART_IR_Mask1) | UART_IR_Mask0;
      /* Configure UART_PFIFO Register*/
      UART0_PFIFO = (UART0_PFIFO & UART_PFIFO_Mask1) | UART_PFIFO_Mask0;
      /*Configure the Receive pin register;*/
      PORTD_PCR6 = (PORTD_PCR6 & PORTD_PCR6_Mask1) | PORTD_PCR6_Mask0;
      /*Configure the Transmit pin register;*/
      PORTD_PCR7 = (PORTD_PCR7 & PORTD_PCR7_Mask1) | PORTD_PCR7_Mask0;
      /* Enable Transmitter and Receiver */
      UART0_C2 = (UART0_C2 & UART_C2_Mask1) | UART_C2_Mask0;
}
"[\CODE]"

My Problem.

The UART_S1_RDRF Flag, Receive Data Register Full Flag, which initiates when the indicated number of Datawords has been received only activates when the FIFO receives the predetermined number of Datawords, the smallest being 1, i.e. 4 bytes. I only want to send one byte as code to the remote sensor. Therefore, I am not able to initiate the interrupt unless I send it as a uint32_t and capture the UART0_D, which only gives me the last Byte! This works now until the code I send exceeds the max Byte value. Furthermore, the transfer time is critical, while I can establish a workaround it is not efficient. Furthermore, I want to improve my knowledge around the detail of this function.

In accordance with my interpretation of the documentation, the datawords are stored in the FIFO. However, through my review of the literature I have not been able to work out how to read the bytes in the FIFO memory. I would really like to know how to overcome this issue.

While I would like to know how to read the FIFO memory, it will not solve the main issue. That is how to get the first received byte to initiate an interrupt and to read that byte as a code by the remote sensor. After trolling through the documentation, I have been looking at Packet Received Flag in the UART_S3 register. I believe I might be able to establish the Packet size to 1 byte and then read the code directly from the UART0_D register. I have hit the wall here as I have reconfigured the registers for this, however, have not been able to effectively establish the interrupt. The flaw in my understanding maybe associated with me enabling the correct IRQ. At the moment I am applying the IRQ_UART0_STATUS, as I assumed that this was the TRQ for all UART0 status registers?

My Question

How can I read individual bytes within the FIFO memory and is there a more elegant way to achieve what I have done in the attached code. Furthermore, in order to use the Packet Received Flag in the UART_S3 register, what is the correct IRQ, if it isn’t IRQ_UART0_STATUS?

Any advice or direction would be greatly appreciated.
 
Last edited by a moderator:
That sounds really involved.

If I understand [in the end] you have a remote device initiating a transmit of a single byte and want to know when it is received to capture it?

I wrote something setting an interrupt on the Rx pin that detects Start bit on Rx. That was trival and would get you a point to wait for the next 9 bits to read?

In setup [after .begin()?]: attachInterrupt(digitalPinToInterrupt( GPS_SRX ), GPS_serialrx_isr, RISING);

The _isr, This turns off the interrupt for the remainder of the transmission then turned it on when message was complete:
Code:
void GPS_serialrx_isr() {
  ccTimeNow_GPS = ARM_DWT_CYCCNT;
  detachInterrupt(digitalPinToInterrupt(GPS_SRX)); // must re-attach interrupt on receive complete
}

Code above used the processor cycle counter to track the time of the START bit. Perhaps it will help you.
 
Status
Not open for further replies.
Back
Top