Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

xmega32E5 and PWM

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR XTINY/MEGAX/AVRX
View previous topic :: View next topic  
Author Message
Michw

Bascom Member



Joined: 18 Oct 2006
Posts: 2

poland.gif
PostPosted: Mon Sep 15, 2025 1:49 pm    Post subject: xmega32E5 and PWM Reply with quote

Hello,
I'm trying to run a TCD5 timer in PWM mode or as a frequency generator to change the port D pins.
Nothing's working for me. Does anyone have a proven method?
Back to top
View user's profile
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 1167

poland.gif
PostPosted: Mon Sep 15, 2025 3:43 pm    Post subject: Reply with quote

Xmega`s dont belong Xtiny/Avrx platform in the Bascom Very Happy They are treated as "normal AVR`s" Very Happy so this is wrong place for the post but I can imagine they are way better than normal AVR`s

Please provide some code that you tried and describe what you want to achieve.

The 32E5 is a little "weird chip" but I have it and can test and eventually help. Simply I dont want to guess what you want to do.

_________________
Check B-Flash -my MCS bootloader app for Android
Back to top
View user's profile Visit poster's website
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 634
Location: Cleveland, OH

usa.gif
PostPosted: Mon Sep 15, 2025 10:39 pm    Post subject: Reply with quote

Michw,
For a “frequency generator” what output waveform do you want, and what frequency range?

The program below is a very SIMPLE sine wave frequency generator.
There is a lot of room for improvement, but it works, and it met my needs for a simple audio signal generator.
Because it is outputting a sine wave the output is on a DAC output pin, DAC0, PortA.2.

Remember that a DDS signal generator outputs a stairstep output, and one has to feed it through a Low Pass Filter to get a clean sine wave output.

Line # 299 in the IDE program listing says: Fout = 1000
This sets the output frequency in Hz.

The Xmega DAC outputs a new sample at 62.5 KHz. So a 1 KHz sine wave is made up of 62.5 samples / period.
A 5 KHz sine wave only has 12.5 samples / period.
A 10 KHz sine wave only has 6.25 samples / period, (Not very many!!!)

Know that even the 10 KHz sine wave will look good once filtered.

If the output you need is simple a pulse or a square wave, then you don’t need to use a DDS signal generator, and you have other options for generating your signal.

This might, however, help to get you started.

JC


Code:

'File: X32E5 DDS Sinewave V1.bas
'Xmega32E5 DDS Program.
'Bascom
'Jay Carter
'April 2014, Revised Feb 2017

'This project is a simple DDS Sinewave generator for audio range signals.
'It outputs a Sine Wave on DAC output PortA.2

'It runs on an XmegaE5 micro that is running at 32 MHz, (i.e. not overclocked).
'It isn't optimized for speed, there is plenty of room for improvement.
'Arrays are Base 0, (Not the default Base 1).
'The Sinewave lookup table holds one full Period of the Sinewave.
'This ignores sinewave symmetry in order to keep it simple.
'Sinewave table has 256 entries, (0-255).
'Therefore can use 1 Byte as the Sinewave Index.
'Table pointer accumulator uses a Word type variable, scaling * 256.
'The upper byte is the Sine Lookup Table Index value!!!
'The full Word type is the DDS accumulator.
'The carry out of the Word is simply ignored.
'Xmega has a 12-Bit DAC, are only using 10 Bits at this time.
'There were several versions prior to this, so the comments may not always be
'up to date!
'This program uses < 10% of the Xmega32E5's memory.

'As structured, the DDS ISR is 62.5 KHz.
'There are 62,500 "Steps" in the output signal.
'For a clean output one MUST feed the signal through a Low Pass Filter.
'How "good" the waveform is, (Amount of Distortion), depends upon the
'output frequency.

'This program calculates the pointer to the next table value in the Main Loop.
'One could do this within the DDS ISR.
'In that case the program would be running mostly within the ISR, and the
'Main Loop could be NULL, or have user interface for setting frequency, etc.
'As long as the pointer to the next value is determined before the next DDS ISR
'interrupt comes along, it really doesn't matter which approach is used.
'Be careful if use Floating Point inside an ISR, it needs special register
'handling.

'This DDS has an update DAC rate of 62.5 KHz.
'During each Intr the new DAC value is loaded into the DAC, and a Flag is set.
'In Main the flag is recognized and the next DAC value is calculated.
'Calculated means determine the next sinewave sample to point to, and output
'on the next interrupt.

'The ISR Frequency determines how fast samples are outputted, and hence how many
'samples will be provided for the Sinewave.
'Output Sine 1 KHz   62.5 Samples / Period
'Output Sine 5 KHz   12.5 Samples / Period
'Output Sine 10 KHz  6.25 Samples / Period

'Note also that the DAC is running at 10 bits, not its full 12 bit resolution.

'Don't forget that with the XmegaE5 and the Timer/Counter C 4 Overflow ISR that
'one has to RESET the Overflow ISR Flag inside the ISR, manually!!!

'Note Well:  Increasing the ISR rate ALSO decreases the time the forground has
'to process the data for the next DAC value.  The calculation is interrupted
'more frequently, so it takes longer.!!  Obvious, once one thinks about it.

'...............................................................................
'Hardware Setup and Notes:
'XMega runs at 2 MHz on startup, default.
'The XMega uses a PDI Programmer, 6-Pin Header is on the board.
'Use the Internal 32 MHz Osc.
'This PCB has a Nokia GLCD installed , which isn't used for this project.


'Hardware:
'Currently set up for my "Blue" Xmega32E5 PCB.
'Has a 4.00 MHz External Xtal installed.

'Available on Edge Connector Pads:
'PortA.1
'PortA.2 = DAC Output, (DAC0), Signal Output, unfiltered
'PortA.3 = DAC Output, (DAC1), Not being used.

'PortC.4 = LED2
'PortC.5 =
'PortC.6 =
'PortC.7 = LED3

'PortD.0 =

'Wired on PCB:
'PortA.4 = PB SW 3  Has External Pull-up resistors
'PortA.6 = PB SW 2  Has External Pull-up resistors
'PortA.7 = PB SW 1  Has External Pull-up resistors

'PortD.1 = LED1   Red LED adjacent the GLCD top right corner, High = On

'PortA.5 BT Module High Side Power Driver control, BT is not installed.

'PortD.4 = GLCD   Data Clock, SCK
'PortD.5 = GLCD   Data In, MOSI
'PortD.6 = GLCD   D/C Mode
'PortD.7 = GLCD   CS\
'PortC.0 = GLCD   GLCD Backlight LED, High = On
'PortC.1 = GLCD   Reset\

'PortR.0 External 4 MHz Xtal
'PortR.1 External 4 MHz Xtal

'-------------------------------------------------------------------------------
   $regfile = "xm32E5def.dat"                               'Micro in use
   $crystal = 32000000                                      'Micro's Clock: 32 MHz

   $hwstack = 192                                           'Hardware stack
   $swstack = 192                                           'Software stack
   $framesize = 192                                         'Frame space

   Config Base = 0                                          'Arrays start with Index 0

   Led1 Alias Portd.1                                       'Led1 Red      High is On
   Led2 Alias Portc.4                                       'Led2 Yellow   High is On
   Led3 Alias Portc.7                                       'LED3 Green    High is On

  ' Scope Alias Portc_out.7                                  'O'Scope Probe

   'Now Configure the Port's Pins for Input or Output mode.
   'Config LEDs:
   Portd_pin1ctrl = &B00000000                              'PortD.1 Control Totem Pole Output
   Portc_pin4ctrl = &B00000000                              'PortC.4 Control Totem Pole Output
   Portc_pin7ctrl = &B00000000                              'PortC.7 Control Totem Pole Output
   Portd_dir.1 = 1                                          'PortD.1 = Output
   Portc_dir.4 = 1                                          'PortC.4 = Output
   Portc_dir.7 = 1                                          'PortC.7 = Output

   'Config PortA.2 for output for the DAC:   (Not necessary)
  ' Porta_pin2ctrl = &B00000000                              'PortA.2 Control Totem Pole Output
  ' Porta_dir.2 = 1                                          'PortA.2 = Output

'....................................................................................................

   Dim J As Byte
   Dim D As Byte
   Dim Lpcnt As Word                                        'Loop Counter

   Dim Ttcnt2 As Word                                       'Tick Toc ISR Counter
   Dim Rvbit As Bit                                         'For Register Setup
   Dim Regdata As Byte                                      'For Register Setup

   Dim Lpcnt1 As Word                                       'Loop Counter
   Dim Lpcnt2 As Word                                       'Loop Counter
   Dim Isrcnt As Word                                       'ISR Counter TCD0, 1 intr q mSec
   Dim Mainlp As Word                                       'Loop Counter, Main Loop

   'Define several Values for the Xmega DAC
   Dim Daccnt As Word                                       'DAC ISR Counter for rollover
   Dim Dacch0val As Word                                    'Word Type Data to Feed DAC Ch0
   Dim Dacch1val As Word                                    'Word Type Data to Feed DAC Ch1

   'Dim DDS Direct Digital Synthesis Variables.
   Dim Sintab(512) As Word                                  'Sin Lookup, Base 1
   Dim Ddstmp As Single                                     'For Sin Table Calcs
   Dim Ddsaccum As Single                                   'DDS Phase Accumulator
   Dim Ddsgain As Single                                    'DDS DAC Gain Factor, <= 1.0
   Dim Ddsindex As Word                                     'Index for SinTab()
   Dim Fout As Single                                       'The desired Output Frequency, in Hz
   Dim Dacflag As Byte                                      'ISR Set Flag for calculating next DAC value in Main
   Dim Dacdata As Word                                      'Data Word for loading DAC with
   Dim Dacdur As Word                                       'Counter for Duration of current tone
   Dim Ddstmpw As Word                                      'Delta Phase * 100
   Dim Ddsaccumw As Word                                    'DDS Phase Accum * 100

   Dim Ddstmpdw As Dword                                    'Delta Phase * 1000, Dword type
   Dim Ddsaccumdw As Dword                                  'DDS Phase  Accum * 1000, Dword Type
   Dim Tmpdw As Dword                                       'Calc variable

   'Dim Arbitrary Waveform Gen Variables:
   Dim Awfgindex As Word                                    'Sin Table Index   BASE 0
   Dim Awfgstep As Word                                     'Sample Table Incr Step Size

'///////////////////////////////////////////////////////////////////////////////
Startup:
   'First set the Clock for 32 MHz via Internal RC Osc:
   Gosub Clockopt1

   'Briefly flash LEDs on start up, show that they work.
   Set Led1
   Waitms 250
   Set Led2
   Waitms 250
   Set Led3
   Waitms 250
   Reset Led1
   Reset Led2
   Reset Led3

'...............................................................................
   'Set up Timer/Counter C4 for DDS ISR:

   'No hardware pins are controlled by this action.
   'The Xmega Interrupt Controller must also be set up for this to function.

   'My Xmega E5 Timer/Counter Setup for a desired Interrupt.  System Clock = 32 MHz.
   'NOTE WELL:  One MUST manually Reset the Overflow Interrupt Flag inside the ISR.
   'Otherwise it keeps retriggering, and ISR rate is very fast, and foreground crawls
   'at one instruction per ISR firing.

   'Given the uC's Clock, set the PreScaler divide by.
   'Note, This PreScaler applies to ALL of the uC's Timer/Counters!
   'Then set the Period for the desired interrupt rate.
   'The T/C will roll over when it reaches TOP, or whatever the Period is set to.
   'Be sure to reset the OVF Flag inside the ISR, or it will retrigger.

   'Test Example:
   'Intr at 1000 Hz for now, i.e. q 1 mSec
   'Clock = 32 MHz.
   'Prescaler is / 64.  32MHz/64 --> 500,000 Hz output of PreScaler.
   '500K/500 = 1000.00 Hz as the OverFlow Intr Rate.
   'Set TCC4_Per = 499 (Roll Over counts as 1)

   'Example: Intr at 62500.0 Hz
   'Clock = 32 MHz.
   'Prescaler is / 64.  32MHz/64 --> 500,000 Hz output of PreScaler.
   '500K/8 = 62500.0 Hz as the OverFlow Intr Rate.
   'Set TCC4_Per = 7 for Div by 8, (Roll Over counts as 1)

   'Example: Intr at 83333.333 Hz
   'Clock = 32 MHz.
   'Prescaler is / 64.  32MHz/64 --> 500,000 Hz output of PreScaler.
   '500K/6 = 83333.333 Hz as the OverFlow Intr Rate.
   'Set TCC4_Per = 5 for Div by 6, (Roll Over counts as 1)

   'Example: Intr at 100,000 Hz
   'Clock = 32 MHz.
   'Prescaler is / 64.  32MHz/64 --> 500,000 Hz output of PreScaler.
   '500K/5 = 100,000.0 Hz as the OverFlow Intr Rate.
   'Set TCC4_Per = 4 for Div by 5, (Roll Over counts as 1)

   'Setup for 62.5 KHz DDS ISR Interrupt Rate:
   Config Tcc4 = Normal , Prescale = 64
   Tcc4_per = 7                                             'TOP for TCC4 @ 62.5 KHz ISR
   On Tcc4_ovf Ticktock2 , Saveall                          'Define ISR Label
   'Enable Tcc4_ovf , Hi                                     'Enable the Overflow ISR

'...............................................................................
   'Set up Timer/Counter C5 as a heartbeat ISR.
   'As the DAC ISR is High Priority, and this is Low Priority, it should be able
   'to run with minimal jitter impact on the DAC output.
   'Set this as LOW priority.
   'Only one prescaler can be used for all of the T/C's on the E5.
   'Prescaler is already set at /64 for TCC4.
   'But still need it in the Instruction!

   'The following example fires the ISR at 100.00 Hz.
   'The ISR counts to 99, plus one for roll over, for a 1 Hz Led Flasher.

   'Clock = 32 MHz.
   'Prescaler is / 64.  32MHz/64 --> 500 kHz output of PreScaler.
   '500 k / 5000 = 100.00 Hz as the OverFlow Intr Rate.
   'Set TCC5_Per = 4999 to set Top to 5000.   (Roll Over counts as 1)

   Config Tcc5 = Normal , Prescale = 64
   Tcc5_per = 4999                                          'Can change this once it works.
   On Tcc5_ovf Heartbeat                                    'Define ISR Label
   Enable Tcc5_ovf , Lo                                     'Enable the Overflow ISR

'....................................................................................................
Premain:
   Gosub Initsintable                                       'Initialize DDS Sin Table
   Gosub Dacsetup                                           'SetUp DAC Signal Output

Inits:
   Ttcnt2 = 0                                               'Init ISR Counter
   Lpcnt = 0                                                'Init Loop Counter

   'Now Enable Global Interrupts and let the fun begin:
   Config Priority = Static , Vector = Application , Hi = Enabled , Med = Enabled , Lo = Enabled
   Enable Interrupts

   'Init Variables:
   Isrcnt = 0                                               'Init ISR Counter to 0
   Dacch0val = 0                                            '4095  'Init Full Scale Mid -range
   Dacch1val = 0                                            '4095  'Init Full Scale  Mid-Range
   Daccnt = 0                                               'Init ISR for DAC Counter
   Awfgindex = 1                                            'Init Sin Table pointer
   Awfgstep = 1                                             'Incr through each sample
   Ddsaccum = 0                                             'Init Phase Accumulator
   Dacflag = 0                                              'Init Flag to not set
   Dacdur = 0                                               'Init Tone Duration Counter


Main:

   'Generate a Fixed DDS Generated Output Signal:
   'DDS ISR fires at 62.5 KHz and updates the DAC with the next value.
   'Main Loop watches for flag from DDS ISR, then calculates the next
   'DAC output value for when the ISR next fires.

   'Prior to starting the loop:
   'Pre-calculate the "Step size" for stepping through the Sin Table, based
   'upon the output frequency, table size, and DAC update rate.

   '*************
   'Set the desired output frequency here, in Hz:
   Fout = 1000                                              '1 kHz Output Freq
   '*************

   Ddsindex = 1                                             'Init DDS Table Index
   Gosub Gensin                                             'Calc Delta Phase for this Output Frequency
   Enable Tcc4_ovf , Hi                                     'Enable DAC ISR as High Interrupt

   'Now let ISR update DAC value, and calculate next value in Main Loop.
   'ISR sets a flag when it executes, so Main Loop knows when to calc the
   'next value.

   'Accumulator is a Word Type, and automatically rolls over at 65K.
   'Its upper byte is the Sin Table Index.

   Do
      'Just watch for DDS ISR to set a flag, indicating that Main should
      'calculate the next DAC output value for the ISR to use.

      If Dacflag = 1 Then
         'Need to Calc the next DAC value before next ISR comes along:
         Ddsaccumw = Ddsaccumw + Ddstmpw                    'Incr Phase Angle (* 256)
         Ddsindex = High(ddsaccumw)                         'Grab upper byte as SinTable Index
         Dacdata = Sintab(ddsindex)                         'Get the DAC Data Word
         Dacflag = 0                                        'Reset the FLAG!
      End If
   Loop

   End

'===============================================================================
'Xmega DACB Ch0 & Ch1 Testing, they feed an Audio Amp Chip.


Dacsetup:
   'The XmegaE5 has one 12 Bit DAC, with two output channels.
   'PortA.2 is DAC0 which this program uses.
   'PortA.3 is DAC1 which is not in use.
   'Bascom can set this up, direct Register setup is not required.
   Config Daca = Enabled , Io0 = Enabled , Io1 = Enabled , Internal_output = Disabled , Channel = Dual , Trigger_ch0 = Disabled , Trigger_ch1 = Disabled , Reference = Avcc , Left_adjusted = Disabled , Event_channel = 0 , Interval = 64 , Refresh = 64
   Return

Ticktock2:
   'This is the DDS ISR.
   'PortC Timer/Counter TCC4 ISR to update the DAC output value.
   'The ISR Rate is set by the PortC Timer/Counter TCC$ setup.
   'This routine outputs the next DAC value and sets a flag for the Main Loop.
   'The Main Loop has to calculate the next value before the ISR fires again.

   'On Entry have: DACData, Word, to load into the DAC.
   'Could just use the Sin Table Index for this.
   'On Exit have: Set DACFlag for Main to notice, and update DAC Calcs.

   'Reset the Overflow Flag inside the ISR!
   Tcc4_intflags = 1                                        'Clr Ovf Intr Flag

   Daca0 = Dacdata                                          'Load DAC with Data Word
   Dacflag = 1                                              'Set Flag, ISR Fired

   Return

'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'DDS Routines:
'10 Bit DDS for now, (Xmega could do 12-Bit DDS).
'Ignore Sine wave symmetry for now.
'One full Period is stored in 256 entry lookup table:

Initsintable:
   'Initialize a Sin Look-Up Table for 1 Period.
   'Ignore Symmetry for now.
   'N = 9, 2^N = 512 Entries in Table.
   'Table has ADC/2 as DC Offset   Set to 2047 as Midpoint.
   'Sin going -1 to +1 full scale maps to 0 to 4095 or 4096...
   'Table is indexed Base 1.
   'Actual table goes: 2047 to  4093 to 2047 to 0 to 2047 over 1 period
   'Storing Single into Word Type Table saves the Integer part of the
   'single type calculation.
   'Using a 512 byte array, 2^9 = 512
   '360 Deg / 512 Samples --> 0.703125 Deg/sample
   '*** Changed to 256 Entry Table, for 1 Byte Index into t=lookup table:
   '2^n = 256, n = 8.
   '360 / 256 = 1.40625 Degree / Sample
   'Note: Changed to Base 0 for arrays with V4.

   For Lpcnt1 = 0 To 255
      Ddstmp = Lpcnt1                                       'Index for table  0-255
      Ddstmp = Ddstmp * 1.40625                             'Deg for this table entry, 0-360
      Ddstmp = Deg2rad(ddstmp)                              'Rads for this table entry, 0 - 2Pi
      Ddstmp = Sin(ddstmp)                                  'Calc Sin for this table entry 0 to 0, range -1 to +1
      'Now Multiply value, ranging -1 to +1, * 2047 so DAC value will range
      'from -2047 to + 2047.  Then add 2047 DC offset to center the DAC
      'so the final DAC range is 0 - 2094  (missing the last value).
      Ddstmp = Ddstmp * 2047                                'Scale for Full Scale of DAC, (0-4095)
      Ddstmp = Ddstmp + 2047                                'Add DC offset to put sin midscale of DAC
      Sintab(lpcnt1) = Ddstmp                               'Store Table Entry
   Next
   Return

Gensin:
   'Calculate the Delta Phase for this Output Frequency
   'This calculates the step size for the lookup table for a given desired
   'output frequency, number of table entries, and DAC update rate.
   'On Entry have: Fout in Hz

   '10-Bit Resolution used in Table, but note that Xmega has a 12-Bit DAC available.
   'On Entry have: Fout  The Output Freq in Hz.  Single Type
   'On Entry have: SinTab()  Sine wave table, Base 0, 1 period's worth of samples.
   'On Entry have: DDSGain  The Gain Factor for the output, <= 1.0
   'Calc the amount of Phase to Add to the Phase Accumulator for the given
   'Input Freq, Lookup Table Size, and Output Clock (Sample Rate).

   'For now assume Xmega is at 32 MHz clock,
   'Sample Rate is 100 kHz, (Interrupt rate, Quite fast). <--- CHANGES with version
   'Have about 320 Instr per Interrupt period for ISR and Main to Share!
   'On Exit have: DDSTmp which is the Delta Phase, i.e. how many samples to
   'skip over to get the next Sine Table sample to play for this Output Freq.
   'On Exit have: DDSTmpW  DDS Delta Phase as Word Type.
   '
   'Note:  Instead of "rounding up" and back down in the calc loop, which is
   'slow, multiple by 100 for two decimal places, or by 1000 to pick up three
   'decimal places, but then ignore the rounding of the 4th decimal place.

   'Note: CHANGED to 255 Entry Table for 1 byte lookup.

   Ddsaccum = 0                                             'Init Phase Accumulator
   Ddsaccumw = 0                                            'Init Phase Accum
   Ddsaccumdw = 0                                           'Init Phase Accum

   'Calc the Delta Phase to Add to the Phase Accumulator
   'This gives the entry location in the Sin Table
   'M = Step size through the table.
   '2^n = Number of entries in 1 period of the sine wave, 1 period.
   '512 entries gives n=9   65535 entries gives n=16, etc.
   'N = the resolution of the phase accumulator.
   'In the language:  M = ((fout)(2^n))/Fref
   'N=1024 , Fref = 100KHz, the DAC Sample output rate, Fout = output Freq in Hz
   'Changed to new, lower ISR Rate of 38461.538 Intr / Sec

   'Skip Gain for now, then add.  It adds a lot of FP math.

   '32MHz / 64 -> 500 kHz,  500 kHz / 5 =  100000 Samples / Sec  (Div = 4+1)
   '32MHz / 64 -> 500 kHz,  500 kHz / 6 =  83333.333 Samples / Sec  (Div = 5+1)
   '32MHz / 64 -> 500 kHz,  500 kHz / 13 =  38461.538 Samples / Sec  (Div = 12+1)
   '32MHz / 64 -> 500 kHz,  500 kHz / 17 = 29411.76  Samples / Sec   (Div = 16+1)
   '32MHz / 64 -> 500 kHz,  500 kHz / 10 = 50000  Samples / Sec   (Div = 9+1)
   '32MHz / 64 -> 500 kHz,  500 kHz / 8 = 62500  Samples / Sec   (Div = 7+1)

   Ddstmp = Fout * 256                                      'Single Type

   'Select the DDS ISR Rate being used at the moment:
   'Calculate the Delta Phase Shift per Interrupt:
   Ddstmp = Ddstmp / 62500.0

   'Now get the Delta Phase as a Word Type, (Scaled * 256)
   Ddstmp = Ddstmp * 256.0                                  'Scale for Integer Math
   Ddstmpw = Ddstmp                                         'Conv Single to Word Type  * 256

   Return                                                   'Await next intr

Heartbeat:
   'Timer/Counter TCC5 ISR for HeartBeat LED1.
   'Fires at 100.00 Hz, q 10 mSec
   'Low Priority
   'Remember to RESET the ISR Flag inside the ISR on the E5's.

   'Flash an LED for kicks:

   Tcc5_intflags = 1                                        'Clr Ovf Intr Flag

   Ttcnt2 = Ttcnt2 + 1                                      'Incr
   If Ttcnt2 < 20 Then
      Set Led1                                              'LED On
   Else
      Reset Led1                                            'Off
   End If
   If Ttcnt2 > 99 Then
      Ttcnt2 = 0                                            'Rollover
   End If
   Return

Clockopt1:
   'Set up the Xmega clock.
   'Run on Internal 32 MHz Osc at 32 MHz
   'Xmega runs at 2MHz on power up.
   'Leave 2 MHz Osc enabled, and enable the Int 32MHz Clock
   Config Osc = Enabled , 32mhzosc = Enabled
   'Wait a bit to allow clocks to start up and stabilize.
   'Note: Haven't yet switched to 32MHz, are at 2MHz, so Waitms 1 = 16 mSec
   Waitms 4                                                 'Wait 64mSec
   'Next configure the systemclock:
   Config Sysclock = 32mhz , Prescalea = 1 , Prescalebc = 1_1
   Waitms 100                                               'Startup Stabilization Delay
   Return


 


The O'scope shows a very poor looking, stairstep "sine wave", and the same signal once it is fed through a low pass filter.

Back to top
View user's profile Visit poster's website
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 634
Location: Cleveland, OH

usa.gif
PostPosted: Tue Sep 16, 2025 3:46 am    Post subject: Reply with quote

If you just want to do a simple Xmega32E5 PWM using Timer/Counter D5, with an output signal on PortD.5, OC5B, (I/O Pin #23)
then try this program to get you started.

Note: I configured the Timer/counter D5 for single slope PWM manually.
(I just set the registers directly.)
When I used:
Config TCD5 = PWM, Prescale = 64, Comparea = Enabled, Resolution = 16
I kept getting a compiler error, although I am not sure why.
(Version 2.0.8.6)

I currently have the Xmega clock running at 32 MHz.
I then divide that clock by 64 to run the PWM module.

The program, as shown below, will give you a PWM Frequency, (repetition rate), of 500 Hz.
The PWM width is set by the TCD5_CCB value, and it ranges from 0 to TCD5_PER.
So with PER set to 100, the resolution of the PWM signal is 100 steps.
With CCB set to 50, (1/2 of the PER value), the PWM width is 50%.
With CCB set to 25, (1/4 of the PER value), the PWM width is 25%.

The PWM Frequency, (repetition rate), with the below program, is:
PWM Freq (Hz) = 32 MHz / (N * PER)
N = The Timer/Counter Prescaler Divisor, (N = 64 in this case).
PER is the value of TCD5_PER
e.g. 32 MHz / ((64 * 1000) -> 500 Hz PWM update rate.

JC

Code:

'Xmega32E5 PWM Test Program
'File: X32E5 PWM Test V2.bas
'Sept. 15, 2025
'JC Bascom

'HW:
'Blue Xmega32E5 PCB with Nokia 5510 GLCD, 4 PB Sw's, LPF Op-Amps.
'Has a 4.00 MHz External Xtal installed.

'PortR.0 External 4 MHz Xtal
'PortR.1 External 4 MHz Xtal

'PortC.4    LED1
'PortC.5    LED2
'PortA.1    LED3
'PortD.5    PWM Output Signal

'V1:  Works.  PWM Signal on PortD.5
'V2:  Works.  Simplified, no Interrupts running.

'-------------------------------------------------------------------------------
   $regfile = "xm32E5def.dat"                               'Micro being used
   $crystal = 32000000                                      'Micro's Clock: 32 MHz

   $hwstack = 192                                           'Hardware stack
   $swstack = 192                                           'Software stack
   $framesize = 192                                         'Frame space

   LED1 Alias PortC.4                                       'LED1 Red      High is On
   LED2 Alias Portc.5                                       'LED2 Yellow   High is On
   LED3 Alias PortA.1                                       'LED3          High is On

   'Now Configure the Port's Pins for Input or Output mode.
   'Config LEDs and PWM Output Signal Pin:
   PortC_pin4ctrl = &B00000000                              'PortD.1 Control Totem Pole Output
   Portc_pin5ctrl = &B00000000                              'PortC.4 Control Totem Pole Output
   PortA_pin1ctrl = &B00000000                              'PortA.1 Control Totem Pole Output
   PortD_pin5ctrl = &B00000000                              'PortD.5 Control Totem Pole Output

   PortC_dir.4 = 1                                          'PortC.4 = Output
   Portc_dir.5 = 1                                          'PortC.5 = Output
   PortA_dir.1 = 1                                          'PortA.1 = Output
   PortD_dir.5 = 1                                          'PortD.5 = Output   PWM Output Signal

'....................................................................................................
   'Variables:
   Dim Lpcnt As Word          'Loop Counter
   Dim HBCnt as Byte          'Counter for Heartbeat LED Flasher ISR

'///////////////////////////////////////////////////////////////////////////////
Startup:
   'First set the Clock for 32 MHz via Internal RC Osc:
   Gosub Clockopt1

PreMain:
   'Briefly flash LEDs on start up, show that they work.
   Gosub FlashLEDs

Main:

   'PWMTest
   'Help says use this in Main, not in a Sub.
   'Config TCD5 = PWM, Prescale = 64, Comparea = Enabled, Resolution = 16

   'Configure PWM on Timer/counter D5 manually:
   'Note:   PER sets the PWM update rate, eg PWM Frequency
   'PWM Freq = 32 MHz / (N*PER)
   'PER = 1000    PWM Freq = 500 Hz
   'PER = 100     PWM Freq = 5 KHz

   'Note:  CCB sets the PWM Value, (The PWM High Time)
   'This ranges from 0 to PER
   'If PER = 1000, CCB = 500, then PWM = 50%
   'If PER = 1000, CCB = 256. then PWM = 25%

   '*****  CHANGE THE CCB VALUE TO CHANGE THE PWM % *****

   TCD5_CTRLA = 5    'PWM Clock Source, currently 32 MHz / 64
   TCD5_CTRLB = 3    'Config Timer/Counter for Normal Mode
   TCD5_CTRLE = &B00000100  'Turn On CCB (Mode Register)

   TCD5_PER = 100  'Resolution of PWM, (Number of steps), Max = 65535 for 16 Bit Resolution
   TCD5_CCB = 50       'PWM value, (PWM Pulse Width), Max = PER value

   'Now start the TC Module:
   TCD5_CTRLGCLR = 0        'Write Bit 5 = 0 to start it

   Do
      NOP
   Loop
   End

FlashLEDs:
   'Flash the PCB's LEDs on Startup
   For LpCnt = 1 to 3
      Set LED1
      Waitms 100
      Set LED2
      Waitms 100
      Set LED3
      Waitms 100

      Reset LED1
      Reset LED2
      Reset LED3
      Waitms 100
   Next LpCnt
   Return

Heartbeat:
   'Timer/Counter TCC5 ISR for HeartBeat LED1.
   'Fires at 100.00 Hz, q 10 mSec
   'Low Priority
   'Remember to RESET the ISR Flag inside the ISR on the E5's.
   'Flash an LED at 1 Hz:

   Tcc5_intflags = 1       'Clr Ovf Intr Flag

   HBCnt = HBCnt + 1       'Incr
   If HBCnt < 10 Then
      Set Led1            'LED On
   Else
      Reset Led1          'Off
   End If
   If HBCnt > 99 Then
      HBCnt = 0           'Rollover
   End If
   Return

Clockopt1:
   'Set up the Xmega clock.
   'Run on Internal 32 MHz Osc at 32 MHz
   'Xmega runs at 2MHz on power up.
   'Leave 2 MHz Osc enabled, and enable the Int 32MHz Clock
   Config Osc = Enabled , 32mhzosc = Enabled
   'Wait a bit to allow clocks to start up and stabilize.
   'Could watch for a Ready Bit to flip.
   Waitms 4                                                 'Wait 64mSec
   'Next configure the systemclock:
   Config Sysclock = 32mhz , Prescalea = 1 , Prescalebc = 1_1
   Waitms 10         'Startup Stabilization Delay
   Return
 
Back to top
View user's profile Visit poster's website
Michw

Bascom Member



Joined: 18 Oct 2006
Posts: 2

poland.gif
PostPosted: Tue Sep 16, 2025 8:50 am    Post subject: Reply with quote

Thank you for your replies.
JC: I'm specifically referring to a hardware-generated square wave from a timer, so I don't have to do it in software.
Commands like "Config TCD5 = PWM, Prescale = 64, Comparea = Enabled, Resolution = 16" work on the AVR, and this microcontroller is giving me errors, even though I also have the latest version of BASCOM.
Your example works, so I just need to dig into the datasheet and find the appropriate configuration registers.

I thought I could quickly run a prototype in Bascom to test it, but it turns out I had some problems Smile
I hope I can get the other timers working Smile
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR XTINY/MEGAX/AVRX All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum