I'm trying to implement a serial stream to send bytes from Arduino Uno to PC (Python code runs on PC using PySerial library). I carefully implemented a C code in a "GCC C Executable Project" using Microship Studio 7.0.2542 and used avrdude to upload the code. Everything seems to be right, but the results are different than expected. I hope you can help me.
The C code implements a circular buffer and uses the USART_RX_vect and USART_TX_vect to handle the USART interrupts.
The expected behavior is (on Arduino side):
- wait a startar signal (2 bytes, 0xff and 0xff) from Python code through USART;
- replies with an Ack signal (2 bytes, 0xff an 0xff) and
- send 10 bytes (for testing purpose) 0x00, 0x01, ..., 0x09.
but
The following happens (on Python side):
- I send the start signal;
- receive the Ack response;
- receive de bytes: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00;
If I send the start signal again, this time I receive: 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00;
and if I send start again: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05
and again: 0x06, 0x07, 0x08, 0x09, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
I plan to use the arduino to controll a servo system end send state variables (like voltages, currents, control signal, reference error, etc.) to PC in real time, so this code is only the beginning.
The Avrdude arguments are -C "C:\Arduino\avrdude\avrdude.conf" -p atmega328p -c arduino -P COM4 -b 115200 -U flash:w:"$(TargetDir)$(TargetName).hex":i in the Microship Studio's "External Tools" configured.
The Build log:
------ Build started: Project: SerialStream, Configuration: Debug AVR ------
Build started.
Project "SerialStream.cproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "D:\Arduino\C-GCC\SerialStream\SerialStream.cproj" (target "Build" depends on it):
Task "RunCompilerTask"
Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils\make.exe all --jobs 8 --output-sync
make: Nothing to be done for 'all'.
Done executing task "RunCompilerTask".
Task "RunOutputFileVerifyTask"
Program Memory Usage : 1102 bytes 3,4 % Full
Data Memory Usage : 50 bytes 2,4 % Full
Warning: Memory Usage estimation may not be accurate if there are sections other than .text sections in ELF file
Done executing task "RunOutputFileVerifyTask".
Done building target "CoreBuild" in project "SerialStream.cproj".
Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').
Target "Build" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Avr.common.targets" from project "D:\Arduino\C-GCC\SerialStream\SerialStream.cproj" (entry point):
Done building target "Build" in project "SerialStream.cproj".
Done building project "SerialStream.cproj".
Build succeeded.
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
The Avrdude log:
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude.exe: Device signature = 0x1e950f (probably m328p)
avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude.exe: erasing chip
avrdude.exe: reading input file "D:\Arduino\C-GCC\SerialStream\Debug\SerialStream.hex"
avrdude.exe: writing flash (1102 bytes):
Writing | ################################################## | 100% 0.21s
avrdude.exe: 1102 bytes of flash written
avrdude.exe: verifying flash memory against D:\Arduino\C-GCC\SerialStream\Debug\SerialStream.hex:
Reading | ################################################## | 100% 0.15s
avrdude.exe: 1102 bytes of flash verified
avrdude.exe: safemode: Fuses OK (E:00, H:00, L:00)
avrdude.exe done. Thank you.
Some thing very weird is that the "Datam Memory Usage" in the Build log do not match the expected. For exaple if I set the buffer size to 300 (OUT_BUFF_SZ in the C code) and the "data" array size to 255 the Build log logs that the memory usage is only 320, I expected more then 550 (300 + 255). Or am I wrong?
Here is the code:
/* * main.c * * Created: 4/24/2022 2:59:01 PM * Author: Maciel B Nunes */ #define F_CPU 16000000UL #define __DELAY_BACKWARD_COMPATIBLE__ #define OUT_BUFF_SZ 30 #define IN_BUFF_SZ 8 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define set_bit(reg,bit) (reg |= (1<<bit)) #define clr_bit(reg,bit) (reg &= ~(1<<bit)) #define tst_bit(reg,bit) (reg &(1<<bit)) #define cpl_bit(reg,bit) (reg ^= (1<<bit)) #define true 0xff #define false 0x00 typedef uint8_t bool; // Types =========================================================================================== typedef volatile struct { uint8_t buff[OUT_BUFF_SZ]; uint16_t head; uint16_t tail; uint16_t count; }OutBuff; // Variables ======================================================================================= OutBuff out; bool volatile done = true; uint8_t volatile terminator[] = {255,255}; uint16_t volatile in_head = 0; uint8_t volatile in_buff[] = {0,0,0,0,0,0,0,0}; // Functions Prototyes ============================================================================= void out_initialize(void); void out_putByte(uint8_t); uint8_t out_flushByte(void); bool out_isEmpty(void); bool out_isFull(void); uint16_t out_getFilledSz(void); void out_clearBuff(void); void initialize(void); void waitForStartSignal(void); void sendStartAck(void); void flush(void); void sendBytes(uint8_t[], uint16_t, uint16_t); void rxHandler(void); void txHandler(void); // Functions ======================================================================================= void out_initialize(){ out_clearBuff(); } void out_putByte(uint8_t b){ out.buff[out.head++] = b; out.head %= OUT_BUFF_SZ; out.count++; } uint8_t out_flushByte(){ uint8_t b = out.buff[out.tail++]; out.tail %= OUT_BUFF_SZ; out.count--; return b; } bool out_isEmpty(){ return out.count == 0; } bool out_isFull(){ return out.count == OUT_BUFF_SZ; } uint16_t out_getFreeSz(){ return OUT_BUFF_SZ - out.count; } uint16_t out_getFilledSz(){ return out.count; } void out_clearBuff(){ out.head = out.tail = out.count = 0; } void setup(){ out_initialize(); done = true; /* Baud rate 1Mb/s, 2 stop bits, no parity and TX and RX interruptions enabled. */ UCSR0A |= (1<<U2X0); // Enables double speed (prescaler 8). UBRR0 = 1; // 1Mb/s. UCSR0B |= ((1<<TXEN0) | (1<<TXCIE0) | (1<<RXEN0) | (1<<RXCIE0)); UCSR0C |= (1<<USBS0); // 2 Stop bits. sei(); } void waitForStartSignal(){ while(true){ in_head = 0; while(in_head < 1); if(in_buff[0] != terminator[0]) continue; while(in_head < 2); if(in_buff[1] != terminator[1]) continue; return; } } void sendStartAck(){ while(!done); UDR0 = terminator[0]; UDR0 = terminator[1]; //sendBytes(terminator, 0, 2); } void flush(){ if(done) txHandler(); } void sendBytes(uint8_t byte_array[], uint16_t start, uint16_t end){ uint16_t free_sz = out_getFreeSz(); uint16_t array_sz = end-start; if(free_sz >= array_sz){ for(uint16_t i=start; i<end ; i++) out_putByte(byte_array[i]); flush(); return; } set_bit(PORTB, PB5); uint16_t i = start, turn_end; while(true){ while(!out_isEmpty()); if(array_sz - i > OUT_BUFF_SZ) turn_end = i + OUT_BUFF_SZ; else turn_end = end; for(; i<turn_end; i++) out_putByte(byte_array[i]); flush(); if(i == end) return; } } void rxHandler(){ in_buff[in_head++] = UDR0; } void txHandler(){ done = false; uint16_t filled_sz = out_getFilledSz(); if(filled_sz > 1){ UDR0 = out_flushByte(); UDR0 = out_flushByte(); } else if(filled_sz > 0){ UDR0 = out_flushByte(); } else{ done = true; } } ISR(USART_RX_vect){ rxHandler(); } ISR(USART_TX_vect){ cli(); txHandler(); sei(); } int main(void){ setup(); set_bit(DDRB, PB5); clr_bit(PORTB, PB5); uint8_t data[255]; for(uint16_t i=0; i<255; i++) data[i] = i; while(true){ waitForStartSignal(); sendStartAck(); sendBytes(data, 0, 10); } }
What is wrong?