ATtiny1604 PWM Output Pin Control

I am trying to control the PWM output from TCA0 timer on an ATtiny1604.

I can configure code to use WO0, WO1, WO2 but as target build will use TWIO, WO1 and WO1 are not available. I’d also like to use USART0, TXD so WO2 is also out of the frame.

I’d like to use WO3 (PA3) for the PWM output but I can’t seem to configure a setting to do this.

Please see code snippet that supports WO0, WO1, WO2.

PA3 is defined as an output pin but I’m struggling to find settings for TCA0 to support a waveform coming out of pin WO3 (PA3).

Please could you suggest where I am going wrong.

void PWM_0_TCA0_init(){
  takeOverTCA0();         			                          // millis() is using TCB0
  PORTMUX_CTRLC |= PORTMUX_TCA00_DEFAULT_gc; 	            // Use default pin
  TCA0.SINGLE.PER = 40000;                                // sets the frequency at 50Hz
  TCA0_SINGLE_CTRLA |= TCA_SINGLE_CLKSEL_DIV8_gc;         //Select division factor (1,2,4,8,16,64,256,1024) but not enabled
  TCA0.SINGLE.INTCTRL = 1 << TCA_SINGLE_OVF_bp;           // Overflow Interrupt Enable: enabled - I want to count PWM pulses

  TCA0_SINGLE_CTRLB = 0; 
  TCA0_SINGLE_CTRLB |= TCA_SINGLE_WGMODE_SINGLESLOPE_gc;  // select waveform generation mode  - fast PWM for servo control  
  
  TCA0_SINGLE_CTRLB |= TCA_SINGLE_CMP0EN_bm ;             // PWM output on PB0 which is WO0 (physical pin 9)
  TCA0_SINGLE_CMP0BUF = TCA0_CMP_Lock;

  // TCA0_SINGLE_CTRLB |= TCA_SINGLE_CMP1EN_bm ;             // PWM output on PB1 which is WO1 (physical pin 8)
  // TCA0_SINGLE_CMP1BUF = TCA0_CMP_Lock;

  // TCA0_SINGLE_CTRLB |= TCA_SINGLE_CMP2EN_bm ;             // PWM output on PB2 which is WO2 (physical pin 7)
  // TCA0_SINGLE_CMP2BUF = TCA0_CMP_Lock;

  TCA0_SINGLE_CTRLA |= TCA_SINGLE_ENABLE_bm;  // enable
}

My platformio.ini to show directing millis() to use TCB0…

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:ATtiny1604]
platform = atmelmegaavr
board = ATtiny1604
framework = arduino

build_unflags = -DMILLIS_USE_TIMERA0    ; stop megaTinyCore using TCA0
build_flags = -DMILLIS_USE_TIMERB0      ; have it use TIMERB0 

board_build.f_cpu = 16000000L

upload_speed = 115200
upload_port = /dev/ttyUSB0

monitor_port = /dev/ttyUSB1
monitor_speed = 115200
monitor_filters = send_on_enter

upload_flags =
    --tool
    uart
    --device
    ATtiny1604
    --uart
    $UPLOAD_PORT
    --clk
    $UPLOAD_SPEED
upload_command = pymcuprog write --erase $UPLOAD_FLAGS --filename $SOURCE

I think I have an answer but it’s not helpful…

Each of the three compare registers TCA0.CMPn can have their output sent to the corresponding WOn pin.

For my 14 pin packaged ATtiny1604 the alternate pin outputs for WO1 and WO2 are not physically available whilst WO0 clashes with the default pins used for the USART0 (and I want to use Serial)

The references to WO3, WO4 and WO5 are special cases where split mode has been configured (TCA0 acts as two 8 bit timers) and each split timer may have its compare register output sent to a pin, either WOn and WO(n+3). This is where the WO5 reference comes from - it is the split twin of WO2.

This is not helpful for me as I need the full 16 bit timer to drive a PWM signal for a servo.

My only option is to use the alternate pin output for the USART0 thus freeing up either WO2 (on PB2) or the alternative output for WO0 (on PB3).

For anyone reading this, you can define the use of the alternative pins for Serial by executing the below in your void setup(){} code

  Serial.swap();
  Serial.begin(Serial_BAUD);