[Solved] freq changing PWM output through TCD on TINNY 814

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I hope to light the LED in breathing mode by PWM drive through TCD in TINNY814.

But there is a problem for me: the duty ratio will not chang while I changing the CMPBSET.

I have tried the code from 

    Code from jstampfl

It still keeping the duty ratio set in initialise function.

 

As the code shows:

/*
 * T817servo12b.c
 *
 * Created: 2/14/2018 20:18:49
 * Author : J.Stampfl
 */
#define F_CPU 20000000ul
#include <avr/io.h>
#include <util/delay.h>
volatile uint32_t knt;

	int main(void)
	{
		//Connect the servos and/or connect LEDs to pins PA4 & PA5
		VPORTA.DIR = 0x30;	//  set PA4 & PA5 to output
		//setup TIMER
		TCD0.CTRLA = 0b01101100;	//CLOCK PER, cnt clk = 4,sync clk = 4 as divisors
		//CLOCK PER IS NOT SET HERE. Just selected.  Default is 6, Total divisor = 6*4*4 = 96
		CPU_CCP = 0XD8;				//Magic number for Configuration Change Protection.  Chapt. 8 in Datasheet
		TCD0.FAULTCTRL = 0x30;		//If you set the fuses, don't need this.
		TCD0.CMPACLR = 94;			// ~0 degree on PA4
		TCD0.CMPBSET = 4095 - 94;	// ~0 degree on PA5
		TCD0.CMPBCLR = 4095;		// max count of timer
		// Start the TIMER
		TCD0.CTRLA |= 1;			// Need |= here.

	while (1)
	{
		for (uint16_t ii = 94;ii < 510;ii=ii+10)   //94 ~ 0 degrees, 509 ~180 degrees
		{
			TCD0.CMPACLR = ii;
			TCD0.CMPBSET = 4094 - ii;
			TCD0.CTRLE = 0b00000001;	// Sync the registers
			_delay_ms(100);
		}
		for (uint16_t ii = 509;ii > 95;ii=ii-10)
		{
			TCD0.CMPACLR = ii;
			TCD0.CMPBSET = 4094 - ii;
			TCD0.CTRLE = 0b00000001;
			_delay_ms(100);
		}

	}
}

We should see the duty ratio changing in PIN5,yet, NO.

 

I just want to use PWM B on PIN5, it is really simple for me:

#define F_CPU 3333333ul
#include <avr/io.h>
#include <util/delay.h>
volatile uint32_t knt;

	int main(void)
	{
		//Connect the servos and/or connect LEDs to pins PA4 & PA5
		VPORTA.DIR = 1<<5;	//  set PA5 to output
		//CLOCK PER IS NOT SET HERE. Just selected.  Default is 6, Total divisor = 6*4*4 = 96
		CPU_CCP = 0XD8;				//Magic number for Configuration Change Protection.  Chapt. 8 in Datasheet
		TCD0.FAULTCTRL = 0x20;		//If you set the fuses, don't need this.
		TCD0.CMPBSET = 4095 - 94;	// ~0 degree on PA5
		TCD0.CMPBCLR = 4095;		// max count of timer
		// Start the TIMER
		TCD0.CTRLA |= 1;			// Need |= here.

	while (1)
	{
		for (uint16_t ii = 94;ii < 510;ii=ii+10)   //94 ~ 0 degrees, 509 ~180 degrees
		{
			TCD0.CMPBSET = 4094 - ii;
			TCD0.CTRLE = 0b00000001;	// Sync the registers
			_delay_ms(10);
		}
		for (uint16_t ii = 509;ii > 95;ii=ii-10)
		{
			TCD0.CMPBSET = 4094 - ii;
			TCD0.CTRLE = 0b00000001;
			_delay_ms(10);
		}

	}
}

the ratio is keeping same :  (TCD0.CMPBCLR - TCD0.CMPBSET)/TCD0.CMPBCLR = 94/4095

 

TCD is complex, I do not master it yet, and the datasheet need to be updated.

Actually there is no CMPC & CMPD, it wasted me much time to find where they output to till I read  post of jstampfl.  

 

 

 

This topic has a solution.
Last Edited: Thu. Oct 31, 2019 - 12:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Checked the  TB3212 - Getting Started with TCD

Still no founds.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't confirm it with a simulation, so I'll answer with just my memory.
Set the AUPDATE bit in TCD0.CTRLC.
Also add a write to TCD.CMPCLR in the for loop.

 

for (uint16_t ii = 94;ii < 510;ii=ii+10)   //94 ~ 0 degrees, 509 ~180 degrees
{
	TCD0.CMPBSET = 4094 - ii;
	TCD0.CMPBCLR = 4095;		// max count of timer
	TCD0.CTRLE = 0b00000001;	// Sync the registers
	_delay_ms(10);
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I showed the TCD PWM sample code in # 18 of this thread.
I'm glad if you can use it as a reference.

 

https://www.avrfreaks.net/forum/solvedattiny-402-setting-dual-pwm-pins-pin-2-pa6-pin-5pa1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kabasan:

I read your sample code.

 

TCD0.CTRLC = TCD_AUPDATE_bm;

This is used to sync CMPxCLR automatically, it will work if you want to change CMPxCLR.

I have set AUPDATE while keeping CMPxCLR not changed, problem keeping exists.

 

Your code is nearly same with mine excpet that you don't change duty ratio while TCD running.

And that is the problem.

The assignment before enabled TCD will work indeed, and the duty ratio is equal to that too.

But, the duty ratio will not change if you change CMPxSET on fly.

 

Maybe we need to assign the CMPxCLR & CMPxSET together, I will try this night.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you looked at the sample, there should have been a comment "<--- Not omissible" in it.
The reason for the comment is simple. This is because the PWM could not be updated during TCD operation without that line.
However, I couldn't find a clear explanation for that part in the data sheet. It is only an experimental result.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kabasan:

If you want to update CMPxCLR, you need to set the AUPDATE bit.

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found the reason : the cycle to refresh CMPxSET is too long to notify the change.  It is a shame for me indeed :)

 

this is the code works for ONE RAMP:

#define tcd_CMPBSET  0x0 
#define tcd_CMPBCLR  0x500 //4095

volatile bool cmpbsetInc = false;
volatile uint16_t cmpbset = tcd_CMPBSET;

void TCD_init(void)
{
	TCD0.CTRLB |= TCD_WGMODE_ONERAMP_gc; /* One ramp mode */
	TCD0.DBGCTRL = 1 << TCD_DBGRUN_bp; 

	uint8_t temp = TCD0.FAULTCTRL | TCD_CMPBEN_bm; //enable PWM B output to PIN
	CPU_CCP = CCP_IOREG_gc;
	TCD0.FAULTCTRL = temp;
}

void ledBreathingBegin(void){
    cmpbsetInc = false;
    cmpbset = tcd_CMPBSET;
    while ((TCD0.STATUS & TCD_ENRDY_bm) == 0);
    TCD0.CMPBSET = cmpbset;
    while ((TCD0.STATUS & TCD_ENRDY_bm) == 0);
	TCD0.CMPBCLR = tcd_CMPBCLR;
	TCD0.CTRLE |= TCD_SYNCEOC_bm;
    TCD_begin();
    
	RTC_INT_ENABLE; 
}

void ledBreathing(void){
    if(cmpbsetInc){
		if(cmpbset<tcd_CMPBCLR)
			cmpbset++;
	    else
			cmpbsetInc = false;
	}else{
	    if(cmpbset>0)
			cmpbset--;
	    else
			cmpbsetInc = true;
    }
    
	while ((TCD0.STATUS & TCD_ENRDY_bm) == 0);
    TCD0.CMPBSET = cmpbset;
	TCD0.CTRLE |= TCD_SYNCEOC_bm;
}

This is part of the whole codes, but it is enough to study how to set the TCD.