ATTINY416 SYNC Signal Generation

121 Views Asked by At

I am trying to code a ATTINY416 to perform the following function with the following inputs;

  • Purpose: Transmit a Byte message of '0x01' every X amount of clock cycles, from the input of an external clock source, and to synchronise the output of this Byte to the rising edge of the external input clock signal.

  • Inputs:

  1. The external clock source is at the frequency of 1.048756MHz, and inputs on PORTA Pin 7.
  2. The outputted byte message will be transmitted on PORTB Pin 2.
  3. The byte message needs to occur every 488.281us (2048Hz) or (every 512 clock cycles).

Has anyone got any recommendations on how to do this? Currently I've just implemented transmitting that byte message out every 488.281us through the use of a DELAY function.

Any tips on performing this delay through counting the externally inputted clock cycles and synchronising the output to the rising edge of the external inputted clock signal would be appreciated.

#define F_CPU 20000000UL
#define DELAY_US 488.281 //488.281us +1us

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

int main(void)
{
    
  CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc;         // Use 20 MHz internal clock as source
  CPU_CCP = CCP_IOREG_gc;                                   // Unlock the IO config registers for writing
  CLKCTRL.MCLKCTRLB = 0;                                    // Disable the prescaler

  while (1)
  {
    //Setup USART and Transmit 0x01 Byte        
    USART0.BAUD = F_CPU*4/921600;                       // Setup BAUD Rate
    USART0.CTRLB = 0x40;                                // TXEN
    PORTB.DIRSET = PIN2_bm;                             // PB2/TX - output
    while( (USART0.STATUS & 0x20) == 0 ){}              // DREIF
    USART0.STATUS = 0x40;                               // clear TXCIF
    USART0.TXDATAL = 0x01;                              // Transmit 0x01
    while( (USART0.STATUS & 0x40) == 0 ){}              // TXCIF
    _delay_us(DELAY_US);
  }
}
1

There are 1 best solutions below

6
Gerhard On

An easy way is to use an interrupt on the IO pin to transmit the byte in a ISR. Count the times the interrupt is called to decide when to transmit. An variation would be to use <util/atomic.h> to count only in the ISR and check the count and transmit in main using an atomic block.

The software just do hardware and interrupt initialization and then idle. The interrupts have predictable timing and would generate predictable and consistent output.

I assume that PORTB Pin 2 is multiplexed to use as USART0 Tx?

If you can change your hardware design to use PA1 -> TXD and PA3 <- XCK. Then you can use the Real Time Counter(RTC) to generate an interrupt every 512 clocks. This is the ideal solution with the least delay and most accuracy depending only on the external clock source.