4.1 Bare Metal Implementation
- The Clock peripheral must run at a
frequency of 20 MHz. The default Clock speed is 3.33 MHz and has, by default, a
prescaler division of six. This code example needs to disable the prescaler and use
the clock to maximum speed.
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, CLKCTRL.MCLKCTRLB & ~CLKCTRL_PEN_bm);
- The TCE and WEX corresponding
register in Port Multiplexer can be set to route the modules outputs to different
ports. In this case, Port A is chosen, which is also the default
port.
PORTMUX.TCEROUTEA = 0x0;
- The CTRLB register of TCE contains
the Enable bits of the compare channels and the bit field that determines the
Waveform Generation mode. In this example channels 0, 1, 2, and 3 are used with a
Single-Slope PWM
mode.
TCE0.CTRLB |= (TCE_CMP0EN_bm | TCE_CMP1EN_bm | TCE_CMP2EN_bm | TCE_CMP3EN_bm);
TCE0.CTRLB |= TCE_WGMODE_SINGLESLOPE_gc;
- Set the DIR bit of the CTRLECLR
register of TCE to ‘
1
’ to set the timer to count clock ticks down (decrementing). The default value of the DIR bit is ‘0
’.TCE0.CTRLECLR = TCE_DIR_bm;
- PER is the buffer of the Period
register of TCE. It is used to set the frequency of the PWM signal using
EQ5.1:
Considering the targeted values for this example:
/* the PER register is always set with the desired value -1, 1000 - 1 = 999, the desired value for a 50us period */ TCE0.PER = 0x3E7;
- The Compare registers are updated
using its buffer to set the duty cycle. The values in the Compare registers can be
set to have random duty cycles like: 20%, 40%, 60%, and 80%. However, these values
are overridden at run-time by updating the CMP registers using their buffers after
the first interrupt will occur. So, we can set these values at 0.
TCE0.CMP0 = 0x00;
TCE0.CMP1 = 0x00;
TCE0.CMP2 = 0x00;
TCE0.CMP3 = 0x00;
- After starting the timer, the duty
cycles will increase every time a compare register’s value match the counter value.
The duty cycles range will be between 0-100%. During the ISR, this happens for every
compare channel. ISR routine for Compare 0
channel:
ISR(TCE0_CMP0_vect) { /* clear the interrupt flag */ TCE0.INTFLAGS = TCE_CMP0_bm; static uint16_t duty_cycle = 0; /* duty cycle update in interrupt */ duty_cycle += 5; if(duty_cycle >= MAX_DUTY_CYCLE) duty_cycle = 0; TCE0.CMP0BUF = duty_cycle; }
- Enable interrupts on compare match
for each of the compare registers of
TCE.
TCE0.INTCTRL = (TCE_CMP0_bm | TCE_CMP1_bm | TCE_CMP2_bm | TCE_CMP3_bm);
- Set the initial value for the TCE’s
counter to
0.
TCE0.CNT = 0x00;
- Set the prescaler to 1 by changing
the CLKSEL bit field in the CTRLA register. To start the counter, the user has to
set the Enable bit in the same
register.
TCE0.CTRLA = TCE_CLKSEL_DIV1_gc;
The last step for configuring the TCE is to enable the module.TCE0.CTRLA |= TCE_ENABLE_bm;
- Set the output routing matrix for the
WEX in the Direct mode and enable dead-time insertion for each pair of two
complementary signals. After making these settings, the four PWM signals generated
from TCE divide into eight complementary signals by the
WEX.
WEX0.CTRLA = WEX_INMX_DIRECT_gc | WEX_DTI0EN_bm | WEX_DTI1EN_bm | WEX_DTI2EN_bm | WEX_DTI3EN_bm;
- Set the desired values for dead-time
using the dead-time registers. The dead-time is measured in peripheral clock ticks.
The equation below explains how the dead-time is
calculated:
WEX0.DTLS = 0x03;
WEX0.DTHS = 0x05;
EQ5.2
- Set the Fault Restart mode condition
and fault signal driving pattern in FAULTCTRL
Register.
/* set fault restart mode to latched mode - fault is active as long as the fault condition is active */ /* to restart from fault in latched mode the user must use a software fault clear command */ WEX0.FAULTCTRL = WEX_FDMODE_LATCHED_gc;
/* drive all pins to low '0' logic when a fault is detected */ WEX0.FAULTCTRL |= WEX_FDACT_LOW_gc;
- Enable the event input A of WEX using
EVCTRLA
Register.
WEX0.EVCTRLA = WEX_FAULTEI_bm;
- Enable fault interrupt (fault
detection) and clear the fault flags during the WEX’s
ISR.
WEX0.INTCTRL = WEX_FAULTDET_bm;
/* WEX fault ISR */ ISR(WEX0_FDFEVA_vect) { /* clear the interrupt flag and fault event flag */ WEX0.INTFLAGS = WEX_FDFEVA_bm | WEX_FAULTDET_bm; }
- Configure the EVENT SYSTEM (EVSYS)
peripheral to generate events on Channel 0. Configure WEX to be the user of the
event generator from Channel 0. Generate a fault using a software event. To stop the
fault, turn off the fault generator channel from EVSYS and clear the fault state
using a software
command.
/* set the WEX0 peripheral as the user of the event generator from channel 0, which is a software event in this example*/ EVSYS.USERWEXA = EVSYS_USER_CHANNEL0_gc;
/* software fault creation, repeat in main loop to see it on LogicA. This is an event generated using a software command */ EVSYS.SWEVENTA = EVSYS_SWEVENTA_CH0_gc;
/* clear fault condition using a software command */ WEX0.CTRLC = WEX_CMD_FAULTCLR_gc;
- Enable WEX’s outputs in order to
generate the eight PWM signals using the OUTOVEN
Register.
/* enables WEX's outputs */ WEX0.OUTOVEN = WEX_OUTOVEN0_bm | WEX_OUTOVEN1_bm | WEX_OUTOVEN2_bm | WEX_OUTOVEN3_bm | WEX_OUTOVEN4_bm | WEX_OUTOVEN5_bm | WEX_OUTOVEN6_bm | WEX_OUTOVEN7_bm;
- Then, the Port A Pins 0-7 (PA0-7) are
set as output by writing a ‘
1
’ to the corresponding bit in the Direction register of the port.PORTA.DIRSET = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm | PIN4_bm | PIN5_bm | PIN6_bm | PIN7_bm;
- After all the modules are configured,
enable global
interrupts.
/* enable global interrupts */ sei();