Arduino Mega 2560 Rev3 Transmision ICR4 via USART to PC

Go To Last Post
65 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi everyone. I have a problem with data transmission from Arduino Mega2560 Rev3 via USART to my computer.  I want to send input capture value (ICR4) 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. For test i send const "test" variable. In first 2min i get correct output but then i get incorrect data. What i mean by that, sometimes i lose byte and my program in Python read incorrect value. Please help me to seciure this transmission. My meansure signal is generate from Arduino Uno TimerOne lib. I use VS code with Platform IO plugin. Here is code:

#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);
}

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)
    ;
}

 

This topic has a solution.
Last Edited: Mon. Jun 20, 2022 - 07:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to AVR Freaks.

TheNew1 wrote:
sometimes i lose byte and my program in Python read incorrect value

So the first question is whether the problem lies in your AVR, or in your Python - that's two unknowns.

 

Start by removing one unknown - what happens if you just watch the AVR output in a terminal ?

 

TheNew1 wrote:
normal printer cable

I'm not sure what that means - what counts as "normal" for a printer cable these days ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Feb 25, 2022 - 05:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:

normal printer cable

 

I'm not sure what that means?

I mean cable from first better electronic store.

TheNew1 wrote:

sometimes i lose byte and my program in Python read incorrect value

 

So the first question is whether the problem lies in your AVR, or in your Python - that's two unknowns.

Python code work properly. I test arduino code in Arduino Uno, and clean atmega 382P and i get wrong value. I recive data with realterm and putty.
 

Start by removing one unknown - what happens if you just watch the AVR output in a terminal ?

At first i see 6411 <- value of test variable, then i see alternately 2841 and 6411

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well the first thing I see, and it may not be your problem is:

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();
}

This code does  not change the system clock prescaler, but you will need to wait for a gcc freak to tell you how it do this properly.

The DS says you need to set the flag to allow the change and then WITHIN 4 machine cycles, change the prescaler bits, not change the prescaler bits and wait 4 cycles......

 

Anyway if this is running on an Arduino mega, you don't need to do that, it's already running at 16MHz, if this is a bare chip, then the fuse settings need to be changed to select the xtal and turn off the clk/8 fuse.

Now to the problem, you want to send a 16 bit binary value using an 8 bit channel, so it must be sent as two bytes, the problem then for the receiver is how to receive these two bytes and know it has them,

one, received them in the correct order, (high/low) or (low/high) and, two, has it received them without lossing one or more bytes, thus getting all of the data following out of order!!!

Normally you use something to sync the receiver so it knows the following two bytes are in the order expected and none are missing.  Develop a protocol that frames the data and permits the receiver to detect errors/overruns/missing data so it can be handle properly, don't just send binary data. 

Perhaps something like <STX> dataH dataL <ETX>   or perhaps <RS> data1 <US> data2    etc.....  Or use a "packet" protocol similar to xmodem....

 

Jim

edit: any time you send data between two computers, you have an endian problem, what comes first the high byte or the low byte, ie. big endian or little endian....

 

FF = PI > S.E.T

 

Last Edited: Fri. Feb 25, 2022 - 07:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The next issue with your code is you are doing slow stuff in a fast ISR() here:

// Input-capture event
ISR(TIMER4_CAPT_vect) {
  // Send the value over UART
  UARTSendValue(static_cast<uint16_t>(test));
}

rather then sending your data using the USART in the ISR(), it would be better to queue your data into a transmit buffer, then in main, if data exists in the buffer, pull the data from the buffer and send the data in your main() function.  That way the sending is independent from the data capture and the sending will not interfere (slow down) your data capture....

 

Jim

 

 

FF = PI > S.E.T

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the ideas. As for the data queue for the transmit buffer and <RS> <US>... maybe someone has done it before and I don't want to "reinvent things". Could you please refer me to well made codes? Or where i can find examples ?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:
I don't want to "reinvent things". Could you please refer me to well made codes? Or where i can find examples ?

Buffered USART comms:  Peter Fluery http://www.peterfleury.epizy.com...

grab his other two libs while your there!

A general purpose serial protocol, S.N.A.P see attached, and code here: https://github.com/PHaroZ/arduin...

Another alternative, convert binary data to ascii text, in this project they are sending ADC data (two bytes) similar to what you want to do:

https://community.atmel.com/proj...

 

Attachment(s): 

 

FF = PI > S.E.T

 

Last Edited: Tue. Mar 1, 2022 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much !!! About links, first link have 404 error.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The edit should fix the link

 

FF = PI > S.E.T

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I dont know if i understand your idea properly. I add queue and  protocol (header,len,value,checksum) and something goes wrong. If you could verify where i do mistake or what shoud i do. Here is my code:


#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/atomic.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

volatile uint16_t Tdiff;
static constexpr uint32_t UART_BAUD_RATE=57600;   
volatile uint16_t test = 6411;


typedef struct __attribute__((packed)) Message {

	uint16_t header;
	uint16_t len;	  
	uint16_t Nx;	   
	uint16_t checksum; 
	struct Message* next;
};


Message* head; 
Message* tail; 


void add_to_queue(uint16_t len, uint16_t Nx, uint16_t checksum) { 
Message* newElement;
    newElement = (Message*)malloc(sizeof(Message)); 

	newElement->header = 0x03;
	newElement->len = len;   
	newElement->Nx = Nx;
    newElement->checksum = checksum;
	newElement->next = NULL;
	if(head == NULL) { 
        tail = newElement;  
        head = newElement;  
    }
    else {
        tail->next = newElement; 
        tail = newElement;  
    }
}


void free_queue() { 
    if(head == NULL)
        return;

    Message* tmp;
    while(head->next != NULL) {
        tmp = head;
        head = head->next;
        free(tmp);
    }
    free(head);
    
    head = NULL;
    tail = NULL;
}


Message* pop_queue() { 
    Message* to_return = NULL;
    if(head == NULL) {
  
        return NULL;
    }
    
    if(head->next != NULL) {
        to_return = head;
        head = head->next;
    } else {
    
        to_return = head;
        head = NULL;
        tail = NULL;
    }
    return to_return;
}

uint8_t calc_checksum(void *data, uint8_t len)  // function to count checksum
{
  uint8_t checksum = 0;
  uint8_t *tmp;
  for(tmp = (uint8_t*)data; tmp < (data + len); tmp++){
                                                // xor all the bytes
    checksum ^= *tmp;                           // checksum = checksum xor value stored in tmp
  }
  return checksum;
}

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 (PD1)
  DDRD |= _BV(PD1);
  // Set baudrate 
  UBRR0 = UBRRValue;
  // Enable transmitter
  UCSR0B |= _BV(TXEN0);
  // Set 8-bit frame format
  UCSR0C |=(1<<UMSEL01)|(3<<UCSZ00);
}
void UARTSendByte(unsigned char value) {
  // Wait until the previous transmission has ended
  while (!(UCSR0A & _BV(UDRE0)))
    ;
  UDR0 = value;
  // Put the data into buffer
}
void UARTSendBytes(uint8_t const* data, size_t length) {
  for (uint8_t const* ptr = data; ptr != (data + length); ptr++) {
    UARTSendByte(*ptr);
  }
}

void UARTSendValue(uint16_t value) {
  UARTSendBytes((uint8_t const*)&value, sizeof(value)); 
}
void UARTSendMessage(Message* message){
	UARTSendValue(message->header);
	UARTSendValue(message->len);
	UARTSendValue(message->Nx);
	UARTSendValue(message->checksum);
}

void ICTimerInit() {
 
  TCCR1B |= _BV(ICES1) | _BV(CS10);

  TIMSK1 |= _BV(ICIE1) | _BV(TOIE1);
}



ISR(TIMER1_CAPT_vect) {
	Tdiff = ICR1; 
}


ISR(TIMER1_OVF_vect) {

}

void NewData(){
	sei();
	
		Message *data = pop_queue();
		if (data!=NULL){

			UARTSendMessage(data);
			free(data);
		}

	cli();
}
int main() {
  cli();  
  resetSystemTimerPrescaler();
  UARTSetup(UART_BAUD_RATE);
  ICTimerInit();
  sei(); 
  
  while (true)
  {
    if(Tdiff){
	    add_to_queue(sizeof(Tdiff), Tdiff, calc_checksum(&Tdiff, sizeof(Tdiff)));
    }
	  NewData();

  }
    
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What is meant by:

TheNew1 wrote:
something goes wrong.

Tell us what you were expecting to happen, what actually happens and how it's different.

What have you done so far to solve your issue, or where are you stuck.

 

Jim

 

 

FF = PI > S.E.T

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay,so lets beginning. This code give me 10-15 messages and stuck. Sometimes wont send any message, another time send over 100 messages. Second problem is still missing data, i mean in struct sometimes example: head switch places with checsum or another paramer. Its looks like all value stepping each sending value or lose one and more bytes ( insted of constant values i see data with diffrent endiannes). Until then, I was also looking for information about the buffer in the Python library (the receiving application is written in this language using pyserial) and nothing came out. I also changed the baudrate in the device manager and that didn't help either.

 


 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:
I was also looking for information about the buffer in the Python library (the receiving application is written in this language using pyserial) and nothing came out. I also changed the baudrate in the device manager and that didn't help either.

Ok so you have two unkonwns, the sending program and the receiving program, lets start by using a known good receiving program, a terminal program, if using windows, something like Tera Term, or Putty...

Then, instead of sending binary data, use a known good library to format your data into an ascii string and send that, using printf().

I have posted a project here that reads the ADC a 10bit value and sends it out the USART as an ascii value string, but that project uses a different compiler then gcc, so you will need a gcc person to help you link avrlib to the usart for that to work....

Here is part of the main were I read the ADC and send it out using printf() in ascii.

/* This putchar works with the M8 UART. It will work with other devices
 * if their UART registers use the same names.
 * For ICC this function links clibs(printf) to USART
 */
int putchar(unsigned char c)
{
    /* if char is LF, send CR first */
    if (c == '\n')
        putchar('\r');
    /* Wait for empty transmit buffer */
    while ( !(UCSRA & (1<<UDRE)) )
        ;
    UDR = c;
    return c;
}

int main(void)
{
    uint16_t pot_value;  // holds ADC value of poteniometer

    init_devices(); // init ports, timer, usart, and ADC
    ADC_ref(1);     // use internal AVCC

    do
    {
        pot_value = ADC_read_ch(0);    //read ADC(0) voltage from poteniometer UNO A0
        OCR1A = pot_value;             //set PWM value (Dim an LED!) PORTB1 UNO D9
        printf("ADC value = %u \n", pot_value); //send ADC data to terminal UNO Serial Monitor
        //insert delay here if desired (100ms)
    }
    while(1); //forever loop

    return 0;
}

This is simple and does the same thing you want to do only your value comes from the timer instead of the ADC, but can be sent the same way, simple, no protocol needed and you can see the result on a terminal window.....  

You can verify that your comm channel is working, and if not, you only have one problem to solve, it must be in the transmitter as the receiver is known good.

AVR txd connects to PC rxd and a common ground connection, baud rates are correct...

 

Once that works, both tx and rx programs are working, change to python rx program, are you getting the same results...

Now run your tx program, can you pass data correctly.

Jim

 

 

FF = PI > S.E.T

 

Last Edited: Thu. Mar 3, 2022 - 09:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are you using or in initializing your setup

 UCSR0C |= (1<<UMSEL01)|_BV(UCSZ01) | _BV(UCSZ00);

For initialization, you should preferably have UCSR0C= what you want, like  UCSR0C = (1<<UMSEL01)| _BV(UCSZ01) | _BV(UCSZ00);  assuming these are all the things you want set

 

With an or you lose confidence in the certainty of everything else, which is an easy way for hidden problems to creep in. 

Being explicit puts a stake in the ground: right here I am 100% sure of all bit settings, regardless of what may have happened before or elsewhere.

Who told you to use or??

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will disclose that I did not read EVERY post in this thread.

 

BUT,

 

UCSR0C |= (1<<UMSEL01)|_BV(UCSZ01) | _BV(UCSZ00);

 Is kinda bugging me BECAUSE:

 // UART settings:
  // * 8 data bits
  // * No parity bits (default)
  // * 1 stop bit (default)
  // * Asynchronous Normal mode (default)

 Is not what you get from the little line I quoted above.

 

Based on page 221 of the Datasheet, Setting UMSEL01, and >i'm Guessing< UMSEL00 cleared puts the MODE of the USART into a 'RESERVED' mode.

 

avrcandies wrote:
With an or you lose confidence in the certainty of everything else, which is an easy way for hidden problems to creep in. 

Yeah, I'll go with that.  But theres also nothing really wrong with using the OR as long as your 'sure'.

 

avrcandies wrote:
Being explicit puts a stake in the ground: right here I am 100% sure of all bit settings, regardless of what may have happened before or elsewhere.

Looks like in this case if they use your thought process they would still be wrong?

 

So, by putting teh USART into a "RESERVED" mode, its operation is undetermined, so  it might work, it might not.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

     avrcandies wrote:

Who told you to use or??

Thanks for verifying. Truth is i learning this by myself and some examples what i found had this line. https://maxembedded.com/2013/09/.... Only (1<<UMSEL01) i added. Perhaps i did not understand it correctly.

 
 
Last Edited: Fri. Mar 4, 2022 - 10:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The article you are referring to is for a mega 16/32.  Your thread is about the mega2560, two different parts, two different data sheets.

 

jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
UCSR0C =(0<<UMSEL01)|(0<<UMSEL00)|(3<<UCSZ00); 

This should be correct configuration for my device if i need asynchronous transmission ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:

UCSR0C =(0<<UMSEL01)|(0<<UMSEL00)|(3<<UCSZ00); 

This should be correct configuration for my device if i need asynchronous transmission ?

All AVR's with a USART default to 8N1, there is no need to even touch this register unless you want something different, one less thing to worry about.

 

Jim

These are not the droids your looking for, move along, move along!

 

FF = PI > S.E.T

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Perhaps something like <STX> dataH dataL <ETX>   or perhaps <RS> data1 <US> data2    etc.....  Or use a "packet" protocol similar to xmodem....

The most normal would be to simply add a carriage return, so you have bytes A,B,CR   

Once you get the carriage return you know the next byte will be A. 

However, this works best, only when no bytes are dropped, or mangled (there is no error checking at all).

If you send your values as ascii numbers, then you can also use the terminal as a substitute

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi again. I followed your idea from putchar and matched it with avr-gcc. To use FDEV methood i must convert cpp file to c, it wouldn't work without it. Sending a fixed value was fine, but when I send a ICR4 value it gets incorrect values, i.e. the ICR4 values ​​increase by a different amount (even 8k difference) when measuring a const frequency. I captured data with realterm and putty to make sure about my measurements. Here is new code:

#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdio.h>

volatile uint16_t Tdiff;
const uint32_t UART_BAUD_RATE=76800;
uint16_t test = 7411;

int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );

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 = (uint16_t)(
      (baseClockFrequency / (uartClockDivider * baudrate)) - 1);

  // Setup TX0 pin as output (PE1)
  DDRE |= _BV(PE1);

  // Set baudrate
  UBRR0 = UBRRValue;
  // Enable transmitter
  UCSR0B |= _BV(TXEN0);

}

int uart_putchar( char c, FILE *stream )
{
    if( c == '\n' )
        uart_putchar( '\r', stream );

    while (!(UCSR0A & _BV(UDRE0)))
    ;
    UDR0 = c;
    return 0;
}

void ICTimerInit() {
 
  TCCR4B |= _BV(ICES4) | _BV(CS40);
  TIMSK4 |= _BV(ICIE4) | _BV(TOIE4);
}

// Input-capture event
ISR(TIMER4_CAPT_vect) {
  // Send the value over UART
  Tdiff = ICR4;
}

// Overflow event
ISR(TIMER4_OVF_vect) {
  // Add the max value of ICR register
  // to indicate that overflow happened
  // timeBetweenCaptures += 0xFFFF;
}

int main() {
  cli();
  UARTSetup(UART_BAUD_RATE);
  ICTimerInit();
  sei();  // enable interrupts

  while (1)
  {
    if (Tdiff){
    stdout = &mystdout;
    // printf("%u\n",test);
    printf("%u\n",Tdiff);

    }

  }

}

 

Last Edited: Sat. Mar 5, 2022 - 01:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:

UCSR0C =(0<<UMSEL01)|(0<<UMSEL00)|(3<<UCSZ00); 

This should be correct configuration for my device if i need asynchronous transmission ?

 

Look at the code in your OP:

TheNew1 wrote:

UCSR0C |= (1<<UMSEL01)|_BV(UCSZ01) | _BV(UCSZ00);

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the OP's past that now Jim.

 

FF = PI > S.E.T

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since your using a multibyte value that can change while reading, you need to do an Atomic read of the Tdiff variable in your main().

 while (1)
  {
      cli(); //gcc has a better way to do atomic reads
      val = Tdiff;
      sei(); // and this too
    if (val){ 
    stdout = &mystdout;
    // printf("%u\n",test);
    printf("%u\n",val);

    }

  }

 

 

FF = PI > S.E.T

 

Last Edited: Fri. Mar 4, 2022 - 07:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

I think the OP's past that now Jim.

 

didn’t seem that way until I mentioned it.  Also, the OP, might want to look at the 2560 data sheet a little more as there might be some other differences that have been missed.  
 

that article the OP is referencing from is for a different AVR.

 

cheerio!

East Coast Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Thanks for the suggestion. I added your idea and still something goes wrong. I mean I'm getting some correct values (16005 timer 4 ticks at 1kHz const square signal) but still getting incorrect value as bouns. All data i capture with putty. Here is the graph from the calculations and the code again:

#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdio.h>

volatile uint16_t Tdiff;
const uint32_t UART_BAUD_RATE=76800;
uint16_t test = 7411;
uint16_t val;

int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM( uart_putchar, NULL, _FDEV_SETUP_WRITE );

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 = (uint16_t)(
      (baseClockFrequency / (uartClockDivider * baudrate)) - 1);

  // Setup TX0 pin as output (PE1)
  DDRE |= _BV(PE1);

  // Set baudrate
  UBRR0 = UBRRValue;
  // Enable transmitter
  UCSR0B |= _BV(TXEN0);

}

int uart_putchar( char c, FILE *stream )
{
    if( c == '\n' )
        uart_putchar( '\r', stream );

    while (!(UCSR0A & _BV(UDRE0)))
    ;
    UDR0 = c;
    return 0;
}

void ICTimerInit() {

  TCCR4B |= _BV(ICES4) | _BV(CS40);
  // Enable input capture and overflow interrupts
  TIMSK4 |= _BV(ICIE4) | _BV(TOIE4);
}

// Input-capture event
ISR(TIMER4_CAPT_vect) {
  // Send the value over UART
  Tdiff = ICR4;
}

// Overflow event
ISR(TIMER4_OVF_vect) {
  // Add the max value of ICR register
  // to indicate that overflow happened
  // timeBetweenCaptures += 0xFFFF;
}

int main() {
  cli();
  UARTSetup(UART_BAUD_RATE);
  ICTimerInit();
  sei();  // enable interrupts

  while (1)
  {
    cli();
    val = Tdiff;
    sei();
    if (val){
    stdout = &mystdout;
    printf("%u\n",val);

    }

  }

}

OX is the number of samples, OY is the difference from two consecutive ICR4 values:

 

Last Edited: Sun. Mar 6, 2022 - 11:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use fdev_setup_stream() instead of the struct macro if you want to do it in C++ not C

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When it will be work in C, i will try modify this to c++.What argument do I need as a stream in this methood? Can you show me example of that ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay,I did some measurements for different input frequency. Measurements of 250Hz, 1kHz, 10kH and 100kHz. Regardless of the signal given, period based on the ICR4 readings was the same, namely approximately from 14404 to 16005 timer4 ticks. Anyone know why is this happening? All data was captured with putty and realterm.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 Regardless of the signal given, 

 How many ticks (timer counts) should you be getting at your different frequencies?

 

 but still getting incorrect value as bouns.

What is bouns? Describe what you are seeing and be clear about it.  For example, 

I expect to get about 3211, but I am getting:

  3210, 3214, 3213, 3532,  3211, 3213, 3211, 1897, 2356,  3216

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Mar 6, 2022 - 06:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Example for calculations like (Next ICR4 value - previous ICR4 value)+ (overflow count*2^16 if exist ) = perioid: for 250Hz - 64000, 1kHz signal - 16000 ticks, 10kHz- 1600, 100kHz - 160. Of course it wasn't clearly in real so i accept +/- 1% of error. I expect this output but i get for example: 250hz - 64505 ticks, 1kHz 16005 ticks, 10kHz 14405-16005 ticks, 100kHz -160005 ticks. For Signals higher than 1kHz i get almost the same output.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you used a scope or better, frequency counter, on your signal generator, to ensure you are setting it properly---so the desired freqs are generated?

You don't want to get too far along and find that you have an issue with the actual signal being created.  What happens to the numbers as you slowly dial up the freq, say from 1000 to 5000 Hz?  Do they change smoothly, then stop all of a sudden?

 

Something seems wrong...you get the captured value in the IRQ, but you never compare (subract) from the previous reading.  The reading by itself means nothing, it is just a count value---you want a time difference.

for example

rdg1=2000   rdg2=6700  diff=5700

rdg1=52000   rdg2=1000  diff approx 65k+1k-52k = 14k (due to rollover)

 

Maybe you do do this, but don't see it in your code

Just start off with this---you don't need the overflow irq (max limit then 65535 ), get that much working

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Mar 6, 2022 - 09:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

      avrcandies wrote:

Something seems wrong...you get the captured value in the IRQ, but you never compare (subract) from the previous reading.  The reading by itself means nothing, it is just a count value---you want a time difference.

for example

rdg1=2000   rdg2=6700  diff=5700

rdg1=52000   rdg2=1000  diff approx 65k+1k-52k = 14k (due to rollover)

i am doing calculations in excel because i thought when i subtract in arduino i might get invalid data. The next version will have this functionality. About better scope/frequency counter, i could get one but on next week. For now i can do measurements only with another arduino as generator with TimerOne.h library.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For now i can do measurements only with another arduino as generator

Well, that means nothing...you want to VERIFY you are delivering a steady & good signal. Use an actual sig generator, so you know there are no issue, or at least verify with a scope.

 

i am doing calculations in excel 

This makes even less sense, since the program you show will print out the same tdiff over & over.  You want to print when you have a NEW tdif

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In this code, Tdiff acts as a clipboard for new registry values ​​(by mistake for I didn't rename, I should use tmp or something else). Only for now! Also, if the code detects a new state in ICP, the ICR4 value will change. Am I right ?
 

Well, that means nothing...you want to VERIFY you are delivering a steady & good signal. Use an actual sig generator, so you know there are no issue, or at least verify with a scope.

before any meansurments i tested my arduino-generator with scope and it work fine, but yes i should use more accurate devices

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


Welcome again. Due to problems at the university, I was able to take measurements only today. With code below i could meansure almost properly perioid from FM modulated signal ( for normally TTL signals i had almost good results)I tested this code on two arduino Mega2560 ( one clone, one original), and at original arduino this code wont work, received only one value regardless of the signal given. On clone program work very well, but sometimes i get this output ( pic). What is wrong with this code/ arduino ? Please help

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

#include <stddef.h>
#include <stdint.h>
#include <string.h>

#define _NOP()                   \
  do {                           \
    __asm__ __volatile__("nop"); \
  } while (0)

static constexpr uint32_t UART_BAUD_RATE{1000000};

/// LED-related functions ///

void LEDSetup() {
  // Set PB7 to output
  DDRB |= _BV(DDB7);
}

void LEDSetState(bool state) {
  if (state) {
    // Set PB7 to HIGH
    PORTB |= _BV(PB7);
  } else {
    // Set PB7 to LOW
    PORTB &= ~(_BV(PB7));
  }
}

void LEDToggle() {
  // Check PB7 state
  if (PINB & _BV(PB7)) {
    LEDSetState(false);
  } else {
    LEDSetState(true);
  }
}

/// UART-related functions ///

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 |= _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

  // 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 ///

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>(ICR4));
}

// Overflow event
ISR(TIMER4_OVF_vect) {

}

int main() {
  cli();  // disable interrupts

  resetSystemTimerPrescaler();
  LEDSetup();
  UARTSetup(UART_BAUD_RATE);
  ICTimerInit();

  sei();  // enable interrupts

  while (true)
    ;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You do many things that seem to mostly move the ball nowhere or an excuse for something extra to go wrong (everything you type has a chance to be wrong).

For example, ledSetup  has 5 lines, plus another line to call it, just to set a ddrb bit....why not simply say, right where it is needed: 

 DDRB = _BV(DDB7); //Set port B, with led on PB7

Nothing else needed, no extra typing errors or hunting around to look up & verify what you did elsewhere.

 

you have this: 

void LEDSetState(bool state) {

with "state".  however the port itself (hi or low) contains the state...why the duplication and all of the overhead to keep them matched?    In some much more complicated cases, such shadow variables may prove useful, but it is fluff here.  

If you want to turn the led on, turn it on. If you wan tit off , turn it off...no extra fluffery is needed.

 

what the point of this 

  // Send the value over UART

when the next line clearly says

  UARTSendValue(static_cast<uint16_t>(ICR4));

There is no need to "invent" lines that don't really need to exist.  There is plenty that does need created and attended to.  The point being, if you concentrate on the things that need done, progress will happen.  We tend to find the easy things, even if they don't contribute anything to the solution.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Apr 23, 2022 - 09:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are right, i overcomplicated code a little. Did you see any more places where this code could be crash ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the same thing whittled down, much easier to inspect for errors...why are you using the IRQ to do a send?  Bad idea. IRQ should be fast in and out

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#define _NOP()                   \
  do {                           \
    __asm__ __volatile__("nop"); \
  } while (0)

static constexpr uint32_t UART_BAUD_RATE{1000000};

void LEDToggle() {
  PORTB ^=   _BV(PB7) ;  //Toggle the LED, using xor
}

void UARTSetup(uint32_t baudrate) {
  uint32_t const baseClockFrequency = F_CPU;
  uint32_t const uartClockDivider = 16;
  uint16_t const UBRRValue = static_cast<uint16_t>((baseClockFrequency / (uartClockDivider * baudrate)) - 1);

  DDRE |= _BV(PE1);  	 // Setup TX0 pin as output (PE1)
  UBRR0 = UBRRValue;  	 // Set baudrate
  UCSR0B |= _BV(TXEN0);  // Enable transmitter
  UCSR0C |= _BV(UCSZ01) | _BV(UCSZ00);  // Set 8-bit frame format
}

void UARTSendByte(uint8_t value) {
  while (!(UCSR0A & _BV(UDRE0))); // Wait until the previous transmission has ended
  UDR0 = value;                   // Put the data into buffer
}

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));
}

void ICTimerInit() {		      // Use Timer4, because only ICP4 and ICP5 are accessible on Arduino Mega
  TCCR4B |= _BV(ICES4) | _BV(CS40);   // Set capture on rising edge, and prescaler to 1 (timer clocked at F_CLK)
  TIMSK4 |= _BV(ICIE4) | _BV(TOIE4);  // Enable input capture and overflow interrupts
}

void resetSystemTimerPrescaler() {
  CLKPR = _BV(CLKPCE);  // Wait 4 cycles to make sure the change is applied before proceeding
  _NOP();
  _NOP();
  _NOP();
  _NOP();
}

ISR(TIMER4_CAPT_vect) {
  UARTSendValue(static_cast<uint16_t>(ICR4)); // Send the value over UART
}

ISR(TIMER4_OVF_vect) {
}

int main() {
  cli();  // disable interrupts

  resetSystemTimerPrescaler();
  DDRB |= _BV(DDB7);  // Set PB7 to output
  UARTSetup(UART_BAUD_RATE);
  ICTimerInit();

  sei();  // enable interrupts

  while (true)

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sun. Apr 24, 2022 - 04:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your code. I will test this tomorrow.

why are you using the IRQ to do a send? Bad idea. IRQ should be fast in and out

I know that... Previously, I used a volatile variable to store ICR4 values and then send via USART when someting was in volatile variable ( if statment ) , but i was getting duplicate values ​​from the timer. I know it sounds funny, but it was.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your code. I will test this tomorrow.

Note this is simply a version that removed a lot of fluff...so now you can more easily look at the actual code, to look for troubles. 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so now you can more easily look at the actual code, to look for troubles. 

Based on previous observations, either the sending via USART is broken (which I doubt since it is very simple code) or the timer interrupts (the moment the sending and the timer interrupt capture new state from ICP). This is this a good starting point for analysis? This code is truly simple, toggle diode, capture state from ICP and send timer ICR value via USART, but give me a lot trouble.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:
Based on previous observations, either the sending via USART is broken (which I doubt since it is very simple code) or the timer interrupts (the moment the sending and the timer interrupt capture new state from ICP). This is this a good starting point for analysis? This code is truly simple, toggle diode, capture state from ICP and send timer ICR value via USART, but give me a lot trouble.
This is why design should be done in a modular/isolated fashion. Develop and test separately each small, isolated part of an entire system so you have "solid building blocks" then you can put these together to form the higher level parts of the solution happy in the knowledge that all contributing parts are proven.

 

Don't try writing the entire solution as one great lump and then spend weeks trying to determine where in the huge pile of stuff the faults lie.

 

(the above is the essence of the modern, Agile approach to software engineering ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What i mean by that, sometimes i lose byte and my program in Python read incorrect value.

Forget about python right now, just send your string to the terminal and see if that works.  Otherwise you don't know whether it is an AVR issue or Python issue.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Forget about python right now, just send your string to the terminal and see if that works.  Otherwise you don't know whether it is an AVR issue or Python issue.

I did it and here's what I get: I run this code on working 2 arduino mega and 2 arduino uno devices (obviously with changes from timer 4 to  timer1) and only arduino mega (clone) works with this code, the rest are sending garbage.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You maybe miss the main point ...use a known PC terminal app (Bray, Putty, TeraTerm, YAT, etc)  to receive---you know a terminal is ready to use and should generally be bug free.

If you have created code on both ends you won't know which end (or both) have problems.  Split the problem in half and get that half (transmitter) working.

I did it and here's what I get:

I run this code on working 2 arduino mega and 2 arduino uno devices

You are saying you did try sending to the PC terminal with 4 different boards and only half of them worked? 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Apr 28, 2022 - 08:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay. For now i sended all data from arduino to PC and receive it with Putty and Realterm and i get the same resoult. I check my modules and i finded something. Arduino clone  with i work have CH340 but rest of tested arduino have atmega16U2. ( maybe this is some clue). Second hint i find was timer4 values. I mean i get timer data +/- 7 ticks when i expected +/- 2 tics. What could give me more tics from microcontroler ?

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0



What could give me more tics from microcontroler ?

Why do you think your signal is 100.000000000% steady?  How good is your signal generator?  

Here is an example of a top-line pulse generator (way beyonfd what you need)...good equipment makes the work easier.

 

How much time variation are you talking about (200ns, 2us?)  

Do you account for interrupt delays (that is generally not relevant for timer capture modes, unless you also use the timer time itself during the IRQ).

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For all my test i used this one : https://www.keysight.com/us/en/a.... From this doc i find frequency accuracy: ± (20 ppm + 3 pHz) in 1 year.

How much time variation are you talking about (200ns, 2us?)  

I wanna meansure square signals from 250 Hz to 5kHz with 1-5 Hz frequency deviation and sine shape. Do you ask about it?

Do you account for interrupt delays (that is generally not relevant for timer capture modes, unless you also use the timer time itself during the IRQ).

I only send Timer time to PC via UART, that's all I use it for.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How much time variation are you talking about (200ns, 2us?)  

I mean i get timer data +/- 7 ticks when i expected +/- 2 tics.

Please answer the question...how much actual time variation is this?   Are you triggering reliably?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0



how much actual time variation is this?

 this was from 1kHz square signal without modulation. Plot of results:

 Are you triggering reliably?

as good as generator and microcontroller works.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How much time variation are you talking about (200ns, 2us?)  

I mean i get timer data +/- 7 ticks when i expected +/- 2 tics.

Please answer the question...how much actual time variation is this?

 

You are saying that you don't know how much time 7 timer ticks represents???    Do you understand that frequency is something else?   

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are saying that you don't know how much time 7 timer ticks represents??? 

 7 ticks represents 0.4375us while 2 ticks is 0.125us. Timer tick * 1/F_CPU <- from this formula i have time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

7 ticks represents 0.4375us while 2 ticks is 0.125us.

Well then why didn't you say so?  Ok, that is something you can look at and find where the time is wasted, or not accounted for, delayed, synchronized, trigger level variation, etc.

It is not yet time to mention frequency.  cheeky

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well then why didn't you say so?

 Sorry about that... just bad day for thinking :/
 

you can look at and find where the time is wasted, or not accounted for, delayed, synchronized, trigger level variation, etc.

what part of code could do that ? I mean what could waste more time than is required ? Wrong timer setup or a lot fluffy code ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


If you use an IRQ, it can have a large latency variability.--you do not use software IRQ for the measurement itself, correct?

A direct timer capture (ICR) can only capture, at best, to the nearest clock tick (and a time difference requires 2 edges, hence double the worst-case uncertainty).

Is your signal risetime straight up?  Any slight ramping could add some offset (though it should be repeatable rather than a random variation).

 

This all also assumes the AVR timebase is rock solid--is it?  Since you are using a crystal, probably so.  An internal RC would typically have a poor cycle-cycle stability, far, far worse than an xtal.

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Wed. May 18, 2022 - 06:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TheNew1 wrote:

I wanna meansure square signals ... and sine shape.

 

Could you clarify that please?

 

You want to measure both square and sinewave signals?

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could you clarify that please?

 I try meansure time from signal like that: https://thottingal.in/blog/2014/...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, i use ISR CAPT_vect and ovf (code above).

A direct timer capture (ICR) can only capture, at best, to the nearest clock tick (and a time difference requires 2 edges, hence double the worst-case uncertainty).

First time i hear that ( maybe bcs i'm still learning about that )

Is your signal risetime straight up? 

I think so...

Since you are using a crystal, probably so.

Yes, i don't have any external crystal to use.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wanna meansure square signals ... and sine shape.

You want to measure a sinewave?  Why?  What about it do you want to measure?  I think not, based on your link.  The sine wave is a low freq source going into the modulator. 

Don't you wan to concentrate on processing/decoding the modulated signal?

 

You have never stated what you are doing other than "measuring things"...now it is time for your FULL & clear explanation of what you are trying to do.  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

now it is time for your FULL & clear explanation of what you are trying to do.

I thought it was clear but if not... At the beginning. I want measure time from square signal. This is the first part. Second part is when i get properly reasults, i go to next step where is signal with FM modulation ( link above) and measure time from modulated signal. Carrier signal: 5kHz, message signal shape: sine, frequency deviation: from 1 to 5 Hz. As i said before i need time from square signal, not sine .

Last Edited: Wed. May 18, 2022 - 08:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, i don't have any external crystal to use.

How are you expecting repeatable results without a crystal? ...did you see the graph in #56? What jitter do you estimate the RC osc has?  It may be very good, but maybe not.  AVR chips in the past specified each cycle time must not vary more than 5% from the previous---so it must be at least that good.  Hopefully most RC osc would not be that awful (unless spread spectrum type).  But they do have lots more jitter than an xtal.

 

rom modulated signal. Carrier signal: 5kHz, message signal shape: sine, frequency deviation

You should not be bringing sin (sine) into the conversation, as it is only a distraction and source of confusion.  The signal could be anything; triangle, sine, parabola, whatever.  You are interested in the decoding of whatever is applied.  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Wed. May 18, 2022 - 10:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I saw it... but i thought i could do this without external crystal. When i saw any example code about measure time, this was not mentioned anywhere. About code. It is correct or no?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I saw it... but i thought i could do this without external crystal. When i saw any example code about measure time, this was not mentioned anywhere. About code. It is correct or no?

 The xtal leave no doubt...for 50 cents why not go that route (or use an EXT xtal osc, some AVR's no longer allow a xtal hookup).  With the RC, it may be ok, but what if you get a tick or two worth of jitter?  The problem, is since it iS the timebase any error becomes hidden (though you might think why is my signal jumping, when it is not).  If you have a spare generator like you use, you can use one as your timebase (with a careful setup).  Note an AVERAGE RC freq might show 3.5000000MHz, but have lots of cyce-to-cycle deviation that gets avged out over many cycles.  

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Hi everyone.

Im end about coding in Arduino Mega 2560 REV 3. I switched to clean ATmega ( for now ATmega 32) and its works perfectly. Still i dont know why this code wont work on Arduino but but here is final code for purpouse from topic done on ATmega 32. Thanks you all for helping.
 

    #define F_CPU 16000000UL
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <avr/interrupt.h>
    #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

    char CaptHI, CaptLO;

    void UART_init(long USART_BAUDRATE)
    {
	    UCSRB |= (1 << RXEN) | (1 << TXEN);
	    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);
	    UBRRL = BAUD_PRESCALE;
	    UBRRH = (BAUD_PRESCALE >> 8);
    }

    void UART_TxChar(char ch)
    {
	    while (! (UCSRA & (1<<UDRE)));
	    UDR = ch ;
    }

    ISR(TIMER1_CAPT_vect)
    {
		    CaptLO = ICR1 & 0xFF;
		    CaptHI = ICR1 >> 8;
		    UART_TxChar(CaptLO);
		    UART_TxChar(CaptHI);
    }

    int main ( )
    {
	    sei();
	    TIMSK=(1<<TICIE1);
	    UART_init(1000000);
	    PORTD = 0xFF;
	    TCCR1A = 0;
	    TCNT1=0;
	    TIFR = (1<<ICF1);
	    TCCR1B = 0x41;
	    while(1){}
    }

 

Last Edited: Mon. Jun 20, 2022 - 07:12 PM