Hi everyone. I have a problem with data transmission from Arduino Mega2560 Rev3 via USART to my computer. It uses the C language to keep the program light and to let me see exactly what's going on. I want to send input capture value (ICR4) s with every edge change to rising.I used USB-USART converter FTDI with RT232RL and normal printer cable to check difference. With both of cables i get the same output. Here is code. Please help someone.
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define F_CPU 16000000
#define _NOP() \
do { \
__asm__ __volatile__("nop"); \
} while (0)
static constexpr uint32_t UART_BAUD_RATE{1000000};
const uint16_t test =6411;
volatile uint16_t startseq = 2;
volatile uint16_t endseq = 3;
void UARTSetup(uint32_t baudrate) {
// UART settings:
// * 8 data bits
// * No parity bits (default)
// * 1 stop bit (default)
// * Asynchronous Normal mode (default)
uint32_t const baseClockFrequency = F_CPU;
uint32_t const uartClockDivider = 16;
uint16_t const UBRRValue = static_cast<uint16_t>(
(baseClockFrequency / (uartClockDivider * baudrate)) - 1);
// Setup TX0 pin as output (PE1)
DDRE |= _BV(PE1);
// Set baudrate
UBRR0 = UBRRValue;
// Enable transmitter
UCSR0B |= _BV(TXEN0);
// Set 8-bit frame format
UCSR0C |= (1<<UMSEL01)|_BV(UCSZ01) | _BV(UCSZ00);
}
void UARTSendByte(uint8_t value) {
// Wait until the previous transmission has ended
while (!(UCSR0A & _BV(UDRE0)))
;
// Put the data into buffer
UDR0 = value;
}
void UARTSendBytes(uint8_t const* data, size_t length) {
for (uint8_t const* ptr = data; ptr != (data + length); ptr++) {
UARTSendByte(*ptr);
}
}
void UARTSendString(char const* string) {
UARTSendBytes(reinterpret_cast<uint8_t const*>(string), strlen(string));
}
template <typename T>
void UARTSendValue(T value) {
UARTSendBytes((uint8_t const*)&value, sizeof(value));
}
/// Timer-related functions ///
void ICTimerInit() {
// Use Timer4, because only ICP4 and ICP5 are accessible on Arduino Mega
// (which is bullshit)
// Set capture on rising edge, and prescaler to 1 (timer should be clocked at
// F_CLK)
TCCR4B |= _BV(ICES4) | _BV(CS40);
// Enable input capture and overflow interrupts
TIMSK4 |= _BV(ICIE4) | _BV(TOIE4);
}
/// General functions ///
// This function configures Timer 1 Channel A (OC1A) as PWM
// with maximum frequency, so you can connect an oscilloscope
// and check the real timer clock
void enableClockTestOutput() {
// Enable Fast PWM mode with OCR1A as TOP for TIM1
// Enable pin output on PB5 (OC1A pin)
DDRB |= _BV(PB5);
// Toggle OC1A on compare match, for 50% PWM.
// Also, Fast PWM mode bits.
TCCR1A |= _BV(COM1A0) | _BV(WGM11) | _BV(WGM10);
// Fast PWM mode bits, also prescaler disabled
TCCR1B |= _BV(WGM12) | _BV(WGM13) | _BV(CS10);
// Set OCR1A to 0, so the PWM will have maximum frequency
// Measure the time of high or low signal part to check the frequency.
OCR1A = 0x0;
}
void resetSystemTimerPrescaler() {
// Make sure that there's no prescaler on Fclk
// To change prescaler, set CLKPCE bit in CLKPR register to 1,
// while simultanously setting the prescaler bits - here, we
// set them to 0 because we don't want any prescaler
CLKPR = _BV(CLKPCE);
// Wait 4 cycles to make sure the change is applied before proceeding
_NOP();
_NOP();
_NOP();
_NOP();
}
// Input-capture event
ISR(TIMER4_CAPT_vect) {
// Send the value over UART
UARTSendValue(static_cast<uint16_t>(test));
}
// Overflow event
ISR(TIMER4_OVF_vect) {
// Add the max value of ICR register
// to indicate that overflow happened
// timeBetweenCaptures += 0xFFFF;
}
int main() {
cli(); // disable interrupts
resetSystemTimerPrescaler();
LEDSetup();
UARTSetup(UART_BAUD_RATE);
ICTimerInit();
// enableClockTestOutput();
sei(); // enable interrupts
while (true)
;
}
Interrupt handlers (ISR) should terminate very fast, sending bytes out a serial interface is definitely not something to be done inside an ISR!
I doubt that your wiring is made for 1MHz.
The Arduino IDE includes a really well working serial interface library. You should use that until you know enough about the board to do such "academic challenges".
Thank you for your answer. I am using VS Code and I am not going to write new frameworks. Perhaps I incorrectly put in the wrong section. If I am using USART with a USB cable, the connection to the computer is correct, right? The Arduino Mega has a USB port, but if I set the configuration in C, I have to use the USART registers to set it up correctly.
Thanks for answer. My first project was created with arduino lib and wont work properly ( propably i wrote wrong code from documentations), so for now i wrote this code to better understand how USART working. I chooise 1MHz bcs this baudrate have almost 0% errors ( table from documentations)
Please distinguish USART from UART. The hardware can handle both the Synchronous and Asynchronous protocol, but the USB Serial implementation uses UART. It's your responsibility to set the Arduino and PC ports to the same baudrates.
So then, if i use USB-UART FTDI FT232RL converter and i have the same output, then i must find another code or program to storage bytes as int in file to make sure if cable/arduino code work properly ?
A cable isn't enough, you need an USB2UART converter. Fortunately the Mega2560 contains one in the form of the ATmega16U2 co-processor on the board. Although the ATmega16U2 theoretically can drive that speed I have some doubts that it can handle the USB traffic at that speed.
Fixed value, my mistake. What am I trying to achieve? I am trying to send an ICR4 value (or even a constant) without losing any data. Why won't I use IDE libraries? I have tried to make the same program with the arduino IDE and I am getting the same results so I am trying to make the same program in C ++ as the Arduino libraries work with the same methods I use there. What circuit am I using? Arduino Mega receives a square signal from the generator, between arduino and computer, I used everything I mentioned at the beginning of the post
And from a 10kHz signal you need to transfer every single wave period?
If you want to use 1 Mbaud to transfer to the PC you must not use the onboard USB2Serial adapter (based on a ATmega16U2), it won't be able to reach that speed. A hardware based approach might fit better, the FTDI ft232rl supports up to 3 Mbaud, so you can try with such a board.