1

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

}
CS010101
  • 11
  • 2
  • Please [edit] your question and show your code as a [mre]. If you don't have problems with the serial output part, and if the corresponding code is not trivial, you might replace it with something more simple like toggling the output pin. – Bodo Jun 07 '23 at 11:28
  • What interface are you sending the byte on? You can do this with only using the timer/counter blocks. – Ludo Jun 07 '23 at 11:33
  • Hi, thanks for your comments. I've edited my response to show the code. So I've done the toggling of the output pin, but really what I need to achieve is synchronising the outputted byte message to the inputted external clock rising edge and then consistently output the byte every (488.281us/2048HZ/512clock cycles). – CS010101 Jun 07 '23 at 17:00

1 Answers1

0

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.

Blindy
  • 65,249
  • 10
  • 91
  • 131
Gerhard
  • 6,850
  • 8
  • 51
  • 81
  • Hi, thanks for your answer. I am fairly new to C and AVR programming so it's a very steep /quick learning curve for me. PORTB Pin 2 is multiplexed such that it can be used as a USART0 Tx. Unfortunately the hardware design is currently absolute, so cannot be changed. With this in mind is the interrupt the way to go? – CS010101 Jun 07 '23 at 17:06
  • You can use EVSYS (for routing PA7 to event channel to TCA/TCB event user) + setup TCA (sync channel) or TCB (async channel) to count positive edges – KIIV Jun 07 '23 at 21:26
  • @KIIV: I checked the datasheet, that can work as well. This should be the preferred solution. – Gerhard Jun 08 '23 at 06:19
  • @KIIV Any tips, documents or examples you know of that I can look up in how to do this? – CS010101 Jun 08 '23 at 08:34
  • Don't know about the internet, i've got some old experiments backed up on github like: https://github.com/kiiv-cz/atmel_projects/blob/main/EvSystemTest/EvSystemTest/main.cpp#L93 (only lines 93 + 96 + 101-104) but seems not to support counting mode on event input. (well you can use TCA_CLK, but it needs synchronous channel and user) – KIIV Jun 08 '23 at 11:22
  • The [datasheet](https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATtiny416-417-814-816-817-Auto-DataSheet-DS40002014C.pdf) is as clear as mud. but it look as if you may be right. – Gerhard Jun 09 '23 at 08:16