Hi, sorry for my C in advance. I'm trying to write a simple echo serial program for my Arduino UNO R3 SMD (ATmega328p) using C and only AVR libraries.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
// buffer and corresponding read/write pointers
#define SIZE 64
uint8_t buffer[SIZE];
uint8_t* buffer_w = buffer;
uint8_t* buffer_r = buffer;
uint8_t is_buffer_empty() {
return buffer_r == buffer_w;
}
uint8_t read() {
uint8_t c = *buffer_r;
buffer_r++;
if (buffer_r >= ((uint8_t*) buffer) + SIZE) {
buffer_r = buffer;
}
return c;
}
void write(uint8_t c) {
*buffer_w = c;
buffer_w++;
if (buffer_w >= ((uint8_t*) buffer) + SIZE) {
buffer_w = buffer;
}
}
void usartInit(unsigned int ubrr) {
// Set baud rate
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;
// Enable transmitter (TX) and receiver (RX)
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
// Set frame format: 8 data bits, 1 stop bit (8N1)
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
// enable USART RX Complete Interrupt
void enableRXCInterapt(uint8_t enabled) {
uint8_t mask = (1 << RXCIE0);
UCSR0B = (UCSR0B & ~mask) | (enabled ? mask : 0);
}
// enable USART Data Register Empty Interrupt
void enableEmptyInterapt(uint8_t enabled) {
uint8_t mask = (1 << UDRIE0);
UCSR0B = (UCSR0B & ~mask) | (enabled ? mask : 0);
}
// USART Data Register Empty Interrupt Handler
ISR(USART_UDRE_vect) {
if (is_buffer_empty()) {
enableEmptyInterapt(0);
}
if (!is_buffer_empty()) {
UDR0 = read();
}
}
// USART RX Complete Interrupt Handler
ISR(USART_RX_vect) {
write(UDR0);
}
void setup() {
usartInit(103); // 103 corresponds to ~9600 baudrate
sei(); // enable avr interrupts
enableRXCInterapt(1);
}
void loop() {
if (!is_buffer_empty()) {
enableEmptyInterapt(1);
}
}
int main(void) {
setup();
while(1) {
loop();
}
}
When I test it using the Arduino CLI monitor, everything works fine:
$ ino monitor -p /dev/ttyACM0
Using default monitor configuration for board: arduino:avr:uno
Monitor port settings:
baudrate=9600
bits=8
dtr=on
parity=none
rts=on
stop_bits=1
Connecting to /dev/ttyACM0. Press CTRL-C to exit.
A #input
A
TEST LONG SENTENCE ........ #input
TEST LONG SENTENCE ........
But when I try to create some Python tests, it gets stuck on reading.
import serial
def get_serial():
ser = serial.Serial()
ser.port = '/dev/ttyACM0'
ser.baudrate = 9600
ser.bytesize = serial.EIGHTBITS
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.open()
return ser
if __name__ == "__main__":
ser = get_serial()
print("write")
ser.write(b'a')
print("read")
print(ser.read())
ser.close()
When using arudino-cli:
write into terminal => TX and RX diode light up and I got same bytes back.
python:
running script => diod RX light up and builtin led, script stack in reading
I also tried
cat -v < /dev/ttyACM0
to see what would happen and I got simmular behaviour, bultin led blinked few times.
I have 2 questions:
- Why does the Python script not work, but using the Arduino CLI does?
- Do you think it is a good idea to learn 'bare metal C' using Arduino, or should I buy a different product?