Go Down

Topic: Arduino Due RS485 (Read 4849 times) previous topic - next topic

rk_on_arduino

I am using Arduino Due board
I used rs485 mode of  USART1
I can transmit but for reception i want to use interrupt enable reception
But i cant?
Please reply if any 

MartinL

#1
Jan 30, 2017, 10:12 am Last Edit: Jan 30, 2017, 10:14 am by MartinL
Hi rk_on_arduino,

If you need to read characters from the serial port from outside the main loop() function, then it's necessary to either set up a timer to poll the serial port at regular intervals, (which is somewhat inefficient, as you're calling both Serial and timer interrupts), or to comment out the USART's interrupt handler function in the Due's "variant.cpp" file, where it's located and copy it into your own sketch.

Currently the Due's "variant.cpp" file is located (at least on my PC) at:

C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.11\variants\arduino_due_x\variant.cpp

In the "variant.cpp" file comment out the interrupt handler for the given USART:

Code: [Select]
void USART1_Handler(void)
{
  Serial2.IrqHandler();
}

Then copy this code into you own sketch outside the setup() and loop() functions.

The Serial2.IrqHandler() function simply reads and writes characters to and from the Due's Tx and Rx ring buffers. To keep things simple, it might be easier to leave the Serial2.IrqHandler() function intact and insert you own code that reads characters with the Serial2.read() function after it. This allows you to pull characters off the Rx ring buffer as they arrive.

This method is somewhat inefficient though, as it defeats the object of having the Rx ring buffer that's designed to hold incoming characters until you get round to reading them in the loop() function. However, it does avoid you having to implement your own means of storing transmitted or received characters in the handler function itself using the USART's registers.

Note that any Arduino updates to the Due's core files will overwrite any changes made to the "variant.cpp"  file.

ard_newbie



...or do not comment anything in variant.cpp, but add this before your setup :

void USART1_Handler(void) __attribute__((weak));
void USART1_Handler(void)
{
  /*Serial2.IrqHandler();*/
// your code here
}

MartinL

#3
Jan 30, 2017, 10:43 am Last Edit: Jan 30, 2017, 10:53 am by MartinL
Hi ard_newbie,

Quote
...or do not comment anything in variant.cpp, but add this before your setup :

void USART1_Handler(void) __attribute__((weak));
void USART1_Handler(void)
{
  /*Serial2.IrqHandler();*/
// your code here
}
Thanks.

That's a much better solution. Avoids having to mess around with the "variant.cpp" file.

rk_on_arduino

Thanks
MartinL & ard_newbie
 Will try and reply you soon and also will upload my code.

My only purpose is Arduino due communication with PC using RS485

I am able to transmit data but i dont know how to read data when USART is operating in RS485 mode

Thanks

rk_on_arduino

Following is my code it transmits data Rs485 but for receive i dont know how to receive
i.e. interrupt enable reception

===========================================================================
void setup()
{
 pinMode(RTS, OUTPUT); //RTS for USART1=Serial2 set as output.
digitalWrite(RTS,LOW);

USART1->US_WPMR = 0x55534100; //Unlock the USART Mode register, just in case. (mine wasn't locked).
USART1->US_MR |= (1u << 0); //Set USART1 mode to RS485.

PIOA->PIO_WPMR = 0x50494F00;   //Unlock PIOA register, just in case. (mine wasn't locked).
 PIOA->PIO_ABSR |= (0u << 14); //Set PIOA14 to 0 => Choosing peripheral A = RTS for D23/PA14. (my whole port was already set to 0)
PIOA->PIO_PDR |= (1u << 14); //: Disables the PIO from controlling the corresponding pin (enables peripheral control of the pin).

Serial.begin(9600);

MeterSerial.begin(9600);   //SERIAL_8N1

Wire.begin();
}

void loop()
{

digitalWrite(RTS,HIGH);
  Serial.println("Sending data");
  MeterSerial.println("wating for char");
  digitalWrite(RTS,LOW);
while(1)
 {


}

}

=========================================================================

rk_on_arduino

Still i cant receive data via RS485 only can transmit
I tried

// Before setup function

void USART1_Handler(void)
{
 
PIOB->PIO_SODR |= PIO_PA12;

 if ((USART1->US_CSR & US_CSR_RXRDY) == US_CSR_RXRDY)
 {
  get_dat = USART1->US_RHR; ;
  Serial.println(get_dat);
 }
 
}

//In setup function


NVIC_EnableIRQ(USART1_IRQn); //enable UART i interrupt controlleren

// in loop function

__enable_irq();

// cant receive data



MartinL

Hi rk_on_arduino,

Personally, if you haven't already, I'd check the physical system. Is the RTS line low when you receive data and is data coming out of the RS-485 transceiver?

Have you successfully tried testing the receiver with a simple sketch, one that doesn't override the USART1_Handler() function and just reads the incoming data with Serial2.read() in the loop()?

rk_on_arduino

Please check my code
when
USART1->US_MR |= (1u << 0)|(1<<11);//rs485 mode of USART1

Then i can transmit only but not receive

and if i changed above to
USART1->US_MR |= (1u << 1)|(1<<11);//HARDWARE HANDSHAKING MODE OF USART1
Then i can receive but not transmit
Code: [Select]

void setup()
{
USART1->US_WPMR = 0x55534100; //Unlock the USART Mode register, just in case. (mine wasn't locked).
 USART1->US_MR |= (1u << 0)|(1<<11);//|(1<<19); //Set USART1 mode to RS485.
  USART1->US_CR |= (0u << 4)|(1u << 5)|(1u<<6);
  pinMode(RTS, OUTPUT); //RTS for USART1=Serial2 set as output.
 
 digitalWrite(RTS,HIGH);
 
PIOA->PIO_WPMR = 0x50494F00;   //Unlock PIOA register, just in case. (mine wasn't locked).
 
  PIOA->PIO_ABSR |= (0u << 14); //Set PIOA14 to 0 => Choosing peripheral A = RTS for D23/PA14. (my whole port was already set to 0)
 
 PIOA->PIO_PDR |= (1u << 14); //: Disables the PIO from controlling the corresponding pin (enables peripheral control of the pin).

Serial.begin(9600);
MeterSerial.begin(9600);   //SERIAL_8N1
Wire.begin();
 inputString.reserve(10);
}


void loop()
{


int mydat = 0;
  Serial.println("Transmitter check");
  digitalWrite(RTS,HIGH);
 
  MeterSerial.println("wating for char");
  digitalWrite(RTS,LOW);
  delay(10);
while(1)
  {
counter++;
   
    if(counter==1000)
    {

     if(MeterSerial.available()>0)
     {
      mydat = MeterSerial.read();
     if(mydat!=0&&mydat!=-1)
      Serial.println(mydat,DEC);
     }
     
      counter = 0;
    }

if(mydat == 115) //decimal value of 's' when received then transmit to check transmitter
    {

digitalWrite(RTS,HIGH);
 
  MeterSerial.println("wating for char");
  digitalWrite(RTS,LOW);
  mydat = 0;
  delay(100);
   
    }

}
}

MartinL

Hi rk_on_arduino,

In the datasheet (page 801) it states that in RS-485 mode the RTS line is controlled by (and is the inverse of) the TXEMPTY bit in the USART interrupt registers. So it shouldn't be necessary to select this using GPIO, but to do this you'll need to activate the RTS1 pin found on pin D23 (PA14).

To enable the RTS1 pin you'll need to switch it perhipheral A on port A (PIOA) with the lines:

Code: [Select]
REG_PIOA_ABSR &= ~PIO_ABSR_P14;   // Ensure that peripheral pin is switched to peripheral A
REG_PIOA_PDR |= PIO_PDR_P14;      // Disable the GPIO and switch to the peripheral

rk_on_arduino

Hi MartinL thanks

With the following code i can transmit and receive via RS485
But i need interrupt enable reception.
How i can do that? Please check my code

Code: [Select]

void setup()
{

pinMode(RTS, OUTPUT); //RTS for USART1
digitalWrite(RTS,LOW);
Serial.begin(9600);
MeterSerial.begin(9600,SERIAL_8N1);   //SERIAL_8N1

USART1->US_WPMR = 0x55534100; //Unlock the USART Mode register, just in case. (mine wasn't locked).
  USART1->US_CR |= US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;
  USART1->US_MR |= 0X8C1;//USART1 IN RS485 mode
  USART1->US_CR |= US_CR_TXEN|US_CR_RXEN;  //Enable Transmitter and Receiver


void loop()
{
 char mydat = 0;
while(1)
  {
while(MeterSerial.available())
     {
         
      mydat =  MeterSerial.read();
     if(mydat!=0)
     {
      Serial.println(mydat);
     
     
     }
     
      if(mydat == 's')  //check if char 's' received if yes then transmit for test
    {
   
      delay(100);
digitalWrite(RTS,HIGH);   //for transmitter RTS HIGH
 
MeterSerial.println("wating for char");
MeterSerial.flush();   //Wait till transmit all char

   digitalWrite(RTS,LOW); 
  delay(100);
 
  mydat = 0;
    }
 }
}




Now I am not getting that how to enable interrupt when receiving data
I have searched and study and found US_IER to enable interrupt for transmitter and receiver
But how to define interrupt function?
I am trying and if success then will upload the code
if any idea then reply




MorganS

Please check my code
Please use the auto-format in the IDE before posting code. The indentation is there for a reason. It makes it much faster for a new person looking at your code to understand the blocks and loops.

It's like asking for someone to find a speck of dirt on the beach.
"The problem is in the code you didn't post."

rk_on_arduino


I tried the following NVIC interrupt but not working

Code: [Select]


void USART1_Handler()
{
 
 PIOA->PIO_SODR |= PIO_PA12;
 

  if ((USART1->US_CSR&US_CSR_RXRDY) == 1)
  {
 
     
      get_dat = USART1->US_RHR;
   
   stringComplete = true;
 
     }
}

void setup()
{

pinMode(RTS, OUTPUT); //RTS for USART1
digitalWrite(RTS,LOW);
Serial.begin(9600);
MeterSerial.begin(9600,SERIAL_8N1);   //SERIAL_8N1

USART1->US_WPMR = 0x55534100; //Unlock the USART Mode register, just in case. (mine wasn't locked).
  USART1->US_CR |= US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;
  USART1->US_MR |= 0X8C1;//USART1 IN RS485 mode
  USART1->US_CR |= US_CR_TXEN|US_CR_RXEN;  //Enable Transmitter and Receiver

NVIC_DisableIRQ(USART1_IRQn);
NVIC_ClearPendingIRQ(USART1_IRQn);

NVIC_SetPriority(USART1_IRQn, 1);
 NVIC_EnableIRQ(USART1_IRQn);

__enable_irq();

}


void loop()
{
 char mydat = 0;
while(1)
  {
counter++;
if(stringComplete == true)
    {
     
        Serial.println(get_dat);
        stringComplete = false;
    }

if(counter >=30000)counter = 0;
}
}



MartinL

#13
Feb 04, 2017, 10:16 am Last Edit: Feb 04, 2017, 10:18 am by MartinL
Hi rk_on_arduino,

Although you've set the USART1 to RS-485 mode, you could try testing the USART1_Handler() interrupt service routine, by adding the Serial2.IrqHandler() (or in your case MeterSerial) function then reading the characters using Serial2.read(). This picks the characters out of the Rx ring buffer as they arrive. It's slightly inefficient, as it sort of defeats the object of using the ring buffer, but be should enable you to test that everything's working OK before optimising your code further:

Code: [Select]
void USART1_Handler(void) __attribute__((weak));
void USART1_Handler(void)
{
  Serial2.IrqHandler();      // Store the incoming character in the Rx ring buffer
  byte c = Serial2.read();   // Pull the character off the Rx ring buffer

  // Your code here...
}

rk_on_arduino

I tried as bellow but not working


Code: [Select]

void USART1_Handler()
{
 MeterSerial.IrqHanler();
 get_dat = Meter.Serial.read();
stringComplete == true;
}

void setup()
{

pinMode(RTS, OUTPUT); //RTS for USART1
digitalWrite(RTS,LOW);
Serial.begin(9600);
MeterSerial.begin(9600,SERIAL_8N1);   //SERIAL_8N1

USART1->US_WPMR = 0x55534100; //Unlock the USART Mode register, just in case. (mine wasn't locked).
  USART1->US_CR |= US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;
  USART1->US_MR |= 0X8C1;//USART1 IN RS485 mode
  USART1->US_CR |= US_CR_TXEN|US_CR_RXEN;  //Enable Transmitter and Receiver

NVIC_DisableIRQ(USART1_IRQn);
NVIC_ClearPendingIRQ(USART1_IRQn);

NVIC_SetPriority(USART1_IRQn, 1);
 NVIC_EnableIRQ(USART1_IRQn);

__enable_irq();

}


void loop()
{
 char mydat = 0;
while(1)
  {
counter++;
if(stringComplete == true)
    {
     
        Serial.println(get_dat);
        stringComplete = false;
    }

if(counter >=30000)counter = 0;
}
}




Go Up