ATTINY202 UART in 100 bytes

Simple question is: Can I hack the attiny 202 uart directly in my code to not load the Serial library and fit it all into the 2k flash of the attiny202 ?
Anyone done it? All my searches found nothing.
Or use another method that can talk to another micro (esp8266) that is reliable?

Details:
I am using an ATTINY202 that does wireless data using SPI.
Awesome job on attinymegacore to get this 2k micro to work in the arduino IDE.
My problem is now I want to transmit the wireless ID stored in the chip to another micro (esp8266) that flashes high power leds depending on the data received.
I was just transmitting led status in a servo signal and hacked the servo chip to turn on/off leds instead of power a motor to rotate a lever.
But now I have a micro (esp8266) instead, and need it to know the ID in the attiny chip, since I'm also sending it data via wifi and it has to know if the data is for this ID. I was going to hack the servo signal to encode the 16 bit ID, but then I realized the attiny202 has a uart and the one wire I use to communicate just happens to be the same pin as the TX pin on the chip.

When I tried to using Serial calls, it loads the library and overflows the 2k flash. Oops. (Same thing happened with my servo output, so I coded it myself instead of using library)
So I started to look into coding my own uart tx without the library. It looks pretty complicated to understand the library code, so I'm hoping someone else might have done this. I only need to transmit, not recv, and can hardcode everything. Any help appreciated.

void attiny_usart0Init(void);
void debugPrint(char * data);


int main(void)
{
	attiny_usart0Init();
	
	debugPrint("TEST 1234567890");

    while (1) 
    {
    }
}

void attiny_usart0Init(void)
{
	PORTA_DIRSET = PIN6_bm;
	PORTA_DIRCLR = PIN7_bm;

	/**********************
	PA6 - TXD
	PA7 - RXD
	**********************/

	// disable interrupts
	USART0_CTRLA = 0<<USART_RXCIE_bp | 0<<USART_TXCIE_bp | 0<<USART_DREIE_bp | 0<<USART_RXSIE_bp | 0<<USART_LBME_bp | 0<<USART_ABEIE_bp | USART_RS485_OFF_gc;

	// set baud at 9600 bps from 5Mhz F_perClk (CHANGE ACCORDINGLY)
	USART0_BAUD = 2083;

	// set operation mode at 9600-n-8-1
	USART0_CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_SBMODE_1BIT_gc | USART_CHSIZE_8BIT_gc;

	// enable UART0 TX only
	USART0_CTRLB = 0<<USART_RXEN_bp | USART_TXEN_bm | 0<<USART_SFDEN_bp | 0<<USART_ODME_bp | USART_RXMODE_NORMAL_gc | 0<<USART_MPCM_bp;

	return;
}

void debugPrint(char * data)
{
	for(uint8_t count=0; data[count]!=0; count++)
	{
		USART0_TXDATAH = 0;
		USART0_TXDATAL = data[count];
		while((USART0_STATUS & USART_TXCIF_bm) == 0);
		USART0_STATUS = USART_TXCIF_bm;
	}

	return;
}

You probably have to changed the BAUD value depending on the CPU clock you are running. There is a formula in the datasheet to get the correct value

There are plenty of examples of simple UART bit-banged routines for ATmega processors. The AVRFreaks forum is one place to look. Here is a timer example

Might need some modifications for the ATtiny202

Thank You!! I can't believe someone answered just what I needed...and so quickly. Now the next person should be able to find it with a search.
And yep, it even added only 100 bytes to my 1300, so 'plenty' of room still left.
Didn't know you can access the hardware registers so easily like that in Arduino code.

I happen to use these TinyAVRs (Attiny816/1616/3216) for a lot of my projects. The code is very easy to port between them.

I took this one from a Microchip example. It makes it easier to enter the baudrate and works with different CPU clockspeeds. At just under 200 bytes still small.

#define BAUDRATE 9600
#define USART0_BAUD_RATE(BAUD_RATE)     ((float)(64 * F_CPU / (16 * (float)BAUD_RATE)) + 0.5)
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#define NUM2STR(N) NUM2STR_(N)
#define NUM2STR_(N) #N

int main(void) {
  F_CPU_init ();
  USART0_init();
  while (1)  {
    USART0_sendString(__DATE__ " @" __TIME__  " with BAUDRATE=" NUM2STR(BAUDRATE)"\r\n");
    _delay_ms(1000);
  }
}

void F_CPU_init () {
  // reconfigure CPU clock prescaler
#if (F_CPU == 20000000)
  /* No division on clock */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
#elif (F_CPU == 16000000)
  /* No division on clock */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0x00);
#elif (F_CPU == 10000000) // 20MHz prescaled by 2
  /* Clock DIV2 */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
#elif (F_CPU == 8000000) // 16MHz prescaled by 2
  /* Clock DIV2 */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_2X_gc));
#elif (F_CPU == 5000000) // 20MHz prescaled by 4
  /* Clock DIV4 */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc));
#elif (F_CPU == 4000000) // 16MHz prescaled by 4
  /* Clock DIV4 */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_4X_gc));
#elif (F_CPU == 1000000) // 16MHz prescaled by 16
  /* Clock DIV16 */
  _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, (CLKCTRL_PEN_bm | CLKCTRL_PDIV_16X_gc));
#else
#ifndef F_CPU
#error "F_CPU not defined"
#else
#error "F_CPU defined as an unsupported value for untuned internal oscillator"
#endif
#endif
}

void USART0_init(void) {
  VPORTA_DIR |= PIN6_bm;                              /* set pin 6 of PORT A (TXd) as output*/
  USART0_BAUD = (uint16_t)(USART0_BAUD_RATE(BAUDRATE));   /* set the baud rate*/
  USART0_CTRLC = USART_CHSIZE0_bm | USART_CHSIZE1_bm; /* set the data format to 8-bit*/
  USART0_CTRLB = USART_TXEN_bm;                      /* enable transmitter*/
}

void USART0_sendChar(char c) {
  while (!(USART0_STATUS & USART_DREIF_bm)) { }
  USART0_TXDATAL = c;
}

void USART0_sendString(char *str) {
  for (size_t i = 0; i < strlen(str); i++) USART0_sendChar(str[i]);
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.