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:
- The external clock source is at the frequency of 1.048756MHz, and inputs on PORTA Pin 7.
- The outputted byte message will be transmitted on PORTB Pin 2.
- 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);
}
}
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 inmainusing 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.