ATtiny402-4pins-pwm-TCA-TCB

This was just my way of teaching myself PWM with as many pins as I could with ATtiny 0-Series 


/* * ATtiny402-TCB-TCA-4port-pwm.c * * Created: 4/17/2023 07:37:36 * Author : Sherman Stebbins */ 
#include <avr/io.h>
/*Using default clock 3.33MHz */
#define TCB_CMP_EXAMPLE_VALUE   (0x03AF) //first two digits adjust phase, second two fine tune frequency
void CLOCK_init (void);void PORT_init (void);void TCB0_init (void);
void TCA0_init(void);void PIN_init(void);void TCA0_hardReset(void);void TCA0_init(void){ /* set waveform output on PORT A */// PORTMUX.TCAROUTEA = PORTMUX_TCA0_PORTA_gc; /* enable split mode */ TCA0.SPLIT.CTRLD = TCA_SPLIT_SPLITM_bm; TCA0.SPLIT.CTRLB = TCA_SPLIT_HCMP0EN_bm /* enable compare channel 0 for the higher byte */ |TCA_SPLIT_LCMP0EN_bm | TCA_SPLIT_HCMP1EN_bm | TCA_SPLIT_LCMP1EN_bm  | TCA_SPLIT_LCMP2EN_bm | TCA_SPLIT_HCMP2EN_bm; /* TCA_SPLIT_LCMP0EN_bm;  enable compare channel 0 for the lower byte "This is the mystry trying to get to a port. */ /* set the PWM frequencies and duty cycles */ // PA1 Low still not working to a port (UPDATE: WORKS GREAT NOW!!) TCA0.SPLIT.LPER = 0xFF; //PERIOD_EXAMPLE_VALUE_L //changes frequency
// (PA3): TCA0.SPLIT.HPER = 0xFF;//PERIOD_EXAMPLE_VALUE_H; TCA0.SPLIT.HCMP1 = 0xFF; // DUTY_CYCLE_EXAMPLE_VALUE_H; TCA0.SPLIT.HCMP2 = 0xFF; // DUTY_CYCLE_EXAMPLE_VALUE_H; TCA0.SPLIT.LCMP0 = 0x01; // PA3 this seems to change period..DUTY_CYCLE_EXAMPLE_VALUE_L  // oh YES Got the low!!!!!! TCA0.SPLIT.HCMP0 = 0x01; // DUTY_CYCLE_EXAMPLE_VALUE_H;  //Changes PA3  TCA0.SPLIT.LCMP1 = 0xFF; // seemed to get PA1 going //changes PA1 TCA0.SPLIT.LCMP2 = 0x06; // Seemed to get PA2 going //changes PA2 TCA0.SPLIT.CTRLA = TCA_SPLIT_CLKSEL_DIV2_gc /* set clock source (sys_clk/16) */ | TCA_SPLIT_ENABLE_bm; /* start timer */}/* must be used when switching from single mode to split mode */void TCA0_hardReset(void){ /* stop timer */ TCA0.SINGLE.CTRLA &= ~(TCA_SINGLE_ENABLE_bm); /* force a hard reset */ TCA0.SINGLE.CTRLESET = TCA_SINGLE_CMD_RESET_gc;}
void CLOCK_init (void){ /* Enable writing to protected register */ CPU_CCP = CCP_IOREG_gc; /* Enable Prescaler and set Prescaler Division to 64 */ CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm; /* Enable writing to protected register */ CPU_CCP = CCP_IOREG_gc; /* Select 32KHz Internal Ultra Low Power Oscillator (OSCULP32K) */ CLKCTRL.MCLKCTRLA = CLKCTRL_CLKSEL_OSC20M_gc; /* Wait for system oscillator changing to finish */ while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) { ; }}
void PORT_init (void){ PORTA_DIR |= PIN6_bm; PORTA_OUT |= PIN6_bm;}
void TCB0_init (void){ /* Load CCMP register with the period and duty cycle of the PWM */ TCB0.CCMP = TCB_CMP_EXAMPLE_VALUE;
/* Enable TCB0 and Divide CLK_PER by 2 */ TCB0.CTRLA |= TCB_ENABLE_bm; TCB0.CTRLA |= TCB_CLKSEL_CLKDIV2_gc; /* Enable Pin Output and configure TCB in 8-bit PWM mode */ TCB0.CTRLB |= TCB_CCMPEN_bm; TCB0.CTRLB |= TCB_CNTMODE_PWM8_gc;}


int main(void){ CLOCK_init(); PORT_init(); TCB0_init(); PORTA.DIR = 0b11111111; TCA0_init(); uint16_t count = 0; uint8_t phase = 0; uint8_t light = 0; static volatile uint8_t direction = 1; while (1) { for(uint16_t i=0;i<50000;i++){ if(++count >2000){ count=0; if(direction){ if(++phase>254){ // phase=0; direction = 0; } } if(direction==0){ phase--; if(phase <=0 ){ // phase=256; direction = 1; light++; if(light>3){light=0;} } } switch (light){ case 0: TCB0.CCMPH = phase; break; case 1: TCA0.SPLIT.HCMP0 = phase; // DUTY_CYCLE_EXAMPLE_VALUE_H;  //Changes PA3 break; case 2: TCA0.SPLIT.LCMP1 = phase; // seemed to get PA1 going //changes PA1 break; case 3: TCA0.SPLIT.LCMP2 = phase; // Seemed to get PA2 going //changes PA2 break; } } } }}