Can UDR be written inside USART_RXC interrupt handler without checking the UDRE flag in AVR ATMega32? - serial-port

I have been trying to understand this code which is supposed to echo each byte received on the AVR's USART interface using interrupt.
#include
#include
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
int main (void)
{
UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
for (;;) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
}
}
ISR(USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
UDR = ReceivedByte; // Echo back the received byte back to the computer
}
I'm having troubles understanding this part
ISR(USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
UDR = ReceivedByte; // Echo back the received byte back to the computer
}
Why isnt the UDRE flag checked here to see if indeed new data can be written, without overwriting previous data? Since we do the same thing in the corresponding polling approach:
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer
Shouldn't there be a checking for the UDRE flag before the UDR = ReceivedByte; line inside the ISR too?
Any insights would be much appreciated.

Short answer is - yes: you can write UDR in any time you want, without any checks ahead.
But, if output buffer is full (the UDRE flag in UCSRA is not set) then written data will be ignored by the transmitter, or, in other words, it will be lost.
The USART module have a double output buffer. That means it is possible to write there two bytes ahead: one is being transmitted right now and one in the buffer will be transmitted later. UDRE flags show when the buffer byte is empty, while TXC flag shows when transmitting byte is pulled out.
So, if you have a way to be sure the transmitter buffer will not be overrun, then it is possible not to check that flag at all. Since receiving of the byte requires exactly the same time as transmitting, you can be sure that RXC interrupts will not be happened more often than bytes will be transmitted, so, it if UDR is not written elsewhere, it is possible to assume that output buffer can always accept at least one-byte, when RXC interrupt happens.
Still, if UDR is written somewhere else, it is possible that output buffer will not be empty, when RXC interrupt is happened, so transmitted echo byte will be lost.
At the other hand, the good programming practice is to leave interrupt handlers as soon as possible. Putting wait loops in the interrupt handler routine is a bad idea. In that case, if you can not be sure the output buffer will be empty on the RXC event, better to either have some kind of output buffer in RAM, which will be processed in UDRE interrupt, or to perform echo outside the RXC interrupt.

Related

Reading multiple bytes in Arduino sent using Pyserial

I'm constantly sending structs of int64 via Pyserial with:
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
value = write_read(struct.pack(">q", int_array[1][i])) #this sends signed int.64 in bytes
print(value)
the struct.pack has this shape, for example:
b'\xff\xff\xff\xff\xff\xff\xff\xef'
and the function write_read consists of:
def write_read(x):
arduino.write((x))
data = arduino.readline()
#the idea is to receive an ACK from the Arduino after 8 bytes (the full
#number)
return data
The code I'm trying to develop in arduino is the following:
void loop() {
// send data only when you receive data:
if (Serial.available() \> 0) {
// read the incoming byte:
incomingByte = Serial.read();
//read 8 bytes and create the result
r= function_to_read_8_last_bytes // or similar
// say what you got:
Serial.print("I received: ");
Serial.printlesultn(r, DEC);
Serial.write("ACK");
}
}
I'm very curious how I could do a robust "read 8 bytes" function.
Should I add some especial character in the Python part to indentify when it ends one value?
Thanks! I'll appreciate any help :)
Given the discussion in the comments, it's hard to receive a stream of bytes and be sure that the receiver is completely synchronized. However let's make some assumptions to ease the problem:
The serial buffer is empty when you connect your laptop to Arduino. This ensures you won't receive spurious data with no meaning. I had this problem happens a lot when the serial connection was ended abruptly by any cause.
You are not constantly sending bytes, Arduino has time to process them until the start of the new sequence.
You only send this data, so there is no need to create a higher level protocol on top of it. Bare in mind that the serial communication is almost just an hardware stack, you receive bytes with no headers.
For assumption 1 you can write a simple piece of code to consume all the spurious bytes in the serial buffer as soon as your main starts from Arudino, so this will be done everytime you connect the serial (as this is also where the power supply comes from). Something like this:
void serialFlush(){
while(Serial.available() > 0) {
char t = Serial.read();
}
}
You can send a "READY" signal back to the Python interface, so that the program knows you are ready to receive data.
Going on with the solution you can implement an easy CRC in python, an additional byte which contains a XOR of all the previous bytes, and you check that in Arduino upon reception complete.
def xor_reduce_long_int(li):
res = 0;
for i in range(8):
mask = (0xFF)<<(i*8)
print(hex(mask))
masked = (li&mask)>>(i*8)
res ^= masked
return res
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
crc=xor_reduce_long_int(int_array[1][i])
value = write_read(struct.pack(">qc", int_array[1][i],crc)) #this sends signed int.64 in bytes
print(value)
And with Arduino I would read 8 bytes when they are available and put them into an unsigned char buffer. I would then define a union that alias such buffer to interpret it as long long int.
typedef struct long_int_CRC
{
union
{
unsigned char bytes[8];
long int data;
};
unsigned char CRC;
}data_T;
// .. Later in main
data_T = received_data;
int received_bytes=0
unsigned char my_CRC = 0;
unsigned char rec_byte= 0;
while( received_bytes < 8 )
{
if(Serial.available() )
{
// Get the byte
rec_byte = Serial.read()
// Store the byte and calc CRC
received_data.bytes[received_bytes] = rec_byte;
my_CRC ^= rec_byte;
// Increment counter for next byte
received_bytes++;
}
}
// Reception complete, check CRC
unsigned char rec_CRC;
if(Serial.available() )
{
rec_CRC = Serial.read()
}
if( my_CRC != rec_CRC )
{
// Something was wrong!
}
// Now access your data as a long int
Serial.print("I received: ");
Serial.printlesultn(received_data.data, DEC);
Serial.write("ACK");

12-bit ADC in MSP430FR2476 seems to only work in 10-bit mode

Here is the problem: I am trying to initialize the 12-bit built-in ADC on MSP430FR2476, but no matter what I do it seems to work at 10 bits. I change the resolution bits in a control register and alas, to no avail. No matter what I have tried nothing helps, always 10 bits. The most significant byte never gets higher than 3. Please help, here is a snippet of the code:
//Configuring ADC
PMMCTL2 |= (INTREFEN); //Internal reference, default 1.5V
ADCCTL0=ADCCTL1 = 0; //Ensuring that the ADC is off
ADCCTL0 |= (ADCSHT_7 + ADCMSC); //sample and hold = 64clk, multiple conversion
ADCCTL1 |= (ADCSHP + ADCSSEL_2 + ADCCONSEQ_1 + ADCDIV_7); //Conversion is triggered
//manually, ADC clock source - SMCLK/8 ~ 2Mhz, sequence of
//channels single conversion,
ADCCTL2 |= (ADCRES_2); //12 bit resolution, no matter what setting I have, no change
ADCMCTL0 |= (ADCSREF_1 + ADCINCH_1); //Employing the internal reference and starting
//conversion from A1 (P1.1)
ADCIE |= ADCIE0; //Activate interrupt
ADCCTL0 |= (ADCON); //Switching ADC on
SYSCFG2 |= (BIT1); //Activate ADC module on the pins (this line
//doesn't do anything for some reason
void adc_convert_begin(){
ADCCTL0 |= ADCENC;
ADCCTL0 |= ADCSC; //Start conversion
//The interrupt simpy send the most significant byte over UART
__attribute__((interrupt(ADC_VECTOR)))
void ADC_ISR(void){
switch(__even_in_range (ADCIV, 0x0C)){
case 0x0C:
adc_data[adc_index] = ADCMEM0;
UCA1TXBUF = (unsigned char)(ADCMEM0>>8);
break;
}
}
The error happens to be here:
ADCCTL2 |= (ADCRES_2);
The idea is the default value is 1, so when I perform an |= operation on the register, the final value turns out to be 3, instead of 2. I need to zero that bit field first!

How can I implement interrupt for serial USART communication for ATmega328P/Arduino Nano?

I have a small project for school that requires me to load data in the EEPROM of an ATmega328P through the USART serial communication. I'm going to figure out the EEPROM read/write myself.
I have problems sending data using interrupts. Basically, I want to have the Arduino Nano loop through code and when I send something through the USART serial communication using the serial monitor of the Arduino IDE, an interruption will occur and the data that was send will be saved in a variable.
My clock is 16 MHz, with a baud rate of 9600; and as I've said I'm using the Arduino IDE.
Here is what I've tried so far:
#define USART_BAUDRATE 9600
#define MYUBRR (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
void setup() {
UCSR0B = (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes
UBRR0H = (MYUBRR >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
UBRR0L = MYUBRR; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
UCSR0B |= (1 << RXCIE0); // Enable the USART Receive Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
}
// Interrupt on receive
ISR (USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR0; // Fetch the received byte value into the variable "ByteReceived"
UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}
// Use the eeprom() function to read/write to EEPROM
void loop() {
}
I've copied and adapted the code from this site (first post).
(In the UCSR0C register, there is no URSEL bit that is mentioned in this post - the datasheet does not mention it and it gives me an error when I try to use it.)
But it seems that the interruption (as it is presented in the last part of the post) is not working for me. I've tested to see if I can read and write in the serial monitor using the following code:
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer
But this makes the controller wait for a data to be sent through the serial monitor, and then it prints it in the serial monitor. I do not want this behaviour.
Here is the datasheet that I've used to check my code: ATmega328P datasheet
Did I do something wrong? Did I forget something in my implementation of USART serial communication interrupt? What is actually wrong with my implementation? why is it not working?
I think you're going wrong here:
ISR (USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR0; // Fetch the received byte value into the variable "ByteReceived"
UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}
In the above code you're basically saying UDR0 = UDR0. You need to give some time between these two lines of code in order to obtain the desired effect. If you take a look at the AVR freaks link you posted, they have this line in between:
while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

Arduino I2C - data stream stopped unexpectedly

I am trying to connect an Arduino Uno to a temperature sensor using I2C. At first, the Arduino can send the data stream, but it stops a few minutes later...
If I restart the board, the Arduino can send the data stream, but again it stops a few minutes later. I wonder whether my code is wrong. Please help me.
/*
Program akses DT-SENSE Temp SENSOR - Arduino
Vizard Vision # 2013
*/
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(38400);
}
int buffer = 0;
int count = 0;
void loop() {
if(count >= 6000) {
count = 0;
}
Wire.beginTransmission(112); // transmit to device #112 (0x70)
// the address specified in the datasheet is 224 (0xE0) --> 1110 0000 = E0H
// but i2c adressing uses the high 7 bits so it's 112 --> 0111 0000 = 70H
Wire.send(0x00);
// command sensor to measure 16 Byte of Temperature Data
Wire.endTransmission();
delay(100);
Wire.requestFrom(112, 2);
// request 2 bytes from slave device #112
if(2 <= Wire.available()) {
// if two bytes were received
buffer = Wire.receive();
// receive high byte (overwrites previous reading)
buffer = buffer << 8;
// shift high byte to be high 8 bits
buffer |= Wire.receive();
// receive low byte as lower 8 bits
buffer = (buffer - 400)/10;
// Conversion data to Temperature (from datasheet)
Serial.print(count);
Serial.print(" Suhu = ");
Serial.print(buffer);
Serial.write(176);
// Unicode value of Degree Symbol
Serial.println("Celsius");
count ++;
Serial.flush();
}
delay(40);
}
There could be a problem here:
if(2 <= Wire.available()) // if two bytes were received
{
buffer = Wire.receive(); // receive high byte (overwrites previous reading)
buffer = buffer << 8; // shift high byte to be high 8 bits
buffer |= Wire.receive(); // receive low byte as lower 8 bits
It will get into the block if there is 1 or 2 bytes available. If there is 2 bytes, it will go through both Wire.receive() and your buffer variable will be setup correctly, and you're happy. If there is only 1 byte, it will pass first Wire.receive(), and on second Wire.receive() you'll have an unexpected behaviour (i.e. documentation does not tell what it does when that happens). So I'd expect it to be blocking until a byte comes, but as it will never come, it blocks infinitely.
Then you'd wonder "why would this ever return a single byte?". And there can be many reasons:
the datasheet may be lying and on very specific circumstances your i2c slave may return a single byte,
your connection is mishandled at one point, and the slave writes both bytes at an incorrect speed making your lib believe it's only one byte,
there's a false contact in your i2c line and under weird circumstances (temperature, pressure, vibration, a storm in Nicaragua) and only one of the two bytes are getting through the connection...
So you should do the following:
if(Wire.available() == 2) // if two bytes were received
{
buffer = Wire.receive(); // receive high byte (overwrites previous reading)
buffer = buffer << 8; // shift high byte to be high 8 bits
buffer |= Wire.receive(); // receive low byte as lower 8 bits
which will make you avoid going through the unexpected behavior!

How to capture a variable stream of characters and process them on a Arduino using serial?

I'm trying to read variable streams of characters and process them on the Arduino once a certain string of bytes is read on the Arduino. I have a sample sketch like the following, but I can't figure out how to compare the "readString" to process something on the Arduino. I would like the Arduino to process "commands" such as {blink}, {open_valve}, {close_valve}, etc.
// Serial - read bytes into string variable for string
String readString;
// Arduino serial read - example
int incomingByte;
// flow_A LED
int led = 4;
void setup() {
Serial.begin(2400); // Open serial port and set Baud rate to 2400.
Serial.write("Power on test");
}
void loop() {
while (Serial.available()) {
delay(10);
if (Serial.available() > 0) {
char c = Serial.read(); // Gets one byte from serial buffer
readString += c; // Makes the string readString
}
}
if (readString.length() > 0) {
Serial.println( readString); // See what was received
}
if (readString == '{blink_Flow_A}') {
digitalWrite(led, HIGH); // Turn the LED on (HIGH is the voltage level).
delay(1000); // Wait for one second.
digitalWrite(led, LOW); // Turn the LED off by making the voltage LOW.
delay(1000); // Wait for a second.
}
Some definitions first:
SOP = Start Of Packet (in your case, an opening brace)
EOP = End Of Packet (in your case, a closing brace)
PAYLOAD = the characters between SOP and EOP
PACKET = SOP + PAYLOAD + EOP
Example:
PACKET= {Abc}
SOP = {
EOP = }
PAYLOAD = Abc
Your code should process one character at a time, and should be structured as a state machine.
When the code starts, the parser state is "I'm waiting for the SOP character". While in this state, you throw away every character you receive unless it's equal to SOP.
When you find you received a SOP char, you change the parser state to "I'm receiving the payload". You store every character from now on into a buffer, until you either see an EOP character or exhaust the buffer (more on this in a moment). If you see the EOP char, you "close" the buffer by appending a NULL character (i.e. 0x00) so that it becomes a standard NULL-terminated C-string, and you can work on it with the standard functions (strcmp, strstr, strchr, etc.).
At this point you pass the buffer to a "process()" function, which executes the operation specified by the payload (1)
You have to specify the maximum length of a packet, and size the receive buffer accordingly. You also have to keep track of the current payload length during the "payload receive" state, so you don't accidentally try to store more payload bytes into the temporary buffer than it can hold (otherwise you get memory corruption).
If you fill the receive buffer without seeing an EOP character, then that packet is either malformed (too long) or a transmission error changed the EOP character into something else. In either case you should discard the buffer contents and go back to "Waiting for SOP" state.
Depending on the protocol design, you could send an error code to the PC so the person typing at the terminal or the software on that side knows the last command it sent was invalid or not received correctly.
Finally, the blink code in you snipped should be replaced by non-blocking "blink-without-delay"-style code (look at the example that come with the Arduino IDE).
(1) Example of a "process" function:
void process(char* cmd) {
if (strcmp(cmd, "open_valve") == 0) {
open_valve();
}
else if (strcmp(cmd, "close_valve") == 0) {
close_valve();
}
else {
print_error("Unrecognized command.");
}
}
It seems you are comparing the string in this statement:
if( readString == '{blink_Flow_A}' )
So I don't get your question re :
but I can't figure out how to compare the "readString" to process something
Are you really asking:
How do I extract the commands from an incoming stream of characters?
If that is the case then treat each command as a "packet". The packet is enclosed in brackets: {}. Knowing that the {} brackets are start and end of a packet, it is easy to write a routine to get at the command in the packet.
Once the command is extracted just go through a if-then-else statement to do what each command is supposed to do.
If I totally misunderstood your question I apologize :)
EDIT:
see http://arduino.cc/en/Tutorial/StringComparisonOperators
if( readString == "{blink_Flow_A}" ) should be correct syntax.
Since you have a statement
Serial.println( readString);
you should see the string received.

Resources