Atmel SAM D - TC and TCC (no ASF) - Page 1
Forum section: electronics / general

author: Franc
author_rank: Regular Contributor
timestamp: October 29, 2016, 07:29:10 pm
content: Hi friends!As I did not find any topic for TC/TCC in Atmel Sam D devices, I opened this.I am in doubt If is possible I use the 'FOR routine' in TCC function as below taking same 'pulse' for both W0x.My TCC0 is supplying 64Khz direct to PA08 through WO and PA09 W0 . For W0 I want to act with a FOR routine as below.Best regards!Code:#include "samd21.h"#include <string.h>#include <stdlib.h>#include <stdint.h>#include "board_defs.h" //board definiçõesuint8_t delay_fase = 0;uint8_t angulo_fase;uint8_t pulsos;void init_TCC0 (void){PM->APBCMASK.reg |= PM_APBCMASK_TCC0;// Enable peripheral clock for TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_TCC0_TCC1;// Disable the GCLKwhile ((GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN));// Enable TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID (TCC0_GCLK_ID) |// TCC0 & TCC1 share same GCLKGCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN (0);while (GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN);// Wait till enabled// TCC0->CTRLA.reg &= ~ (TCC_CTRLA_ENABLE);// Disable TCC0TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 | TCC_CTRLA_PRESCSYNC_GCLK;TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_MFRQ;// Normal PWM// Initialize count to 0TCC0->COUNT.reg = 0;// TCC0->PER.reg = 100;// Set periodTCC0->CC.reg = 21;// Atualiza a frequencia de saida. Atual 63khz// TCC0->WEXCTRL.bit.OTMX = 0x01;// Route CC0 to OTMX;// Enable the timerTCC0->CTRLA.bit.ENABLE = 1;while (TCC0->SYNCBUSY.bit.ENABLE) ;// Wait till timer enabledGPIO_dirOut(DRIVE_R);GPIO_pmuxen(DRIVE_R, PF_MUX_E);for (angulo_fase=0; angulo_fase<16; angulo_fase++){ddDelay_us(delay_fase++);for (pulsos = 0; pulsos < 8; pulsos++){GPIO_dirOut(MODU_OUT);GPIO_pmuxen(MODU_OUT, PF_MUX_E);}ddDelay_ms(1);}}

author: ataradov
author_rank: Super Contributor
timestamp: October 29, 2016, 08:40:01 pm
content: Can you actually explain with words what you want to do?Right now your code makes a pin an output many times in a loop. This will do absolutely nothing after the first iteration.If you want to generate 64 kHz from software, then it is possible, but what it has to do with TC/TCC? And you may want to draw an actual timing diagram of what you want to do.

author: Franc
author_rank: Regular Contributor
timestamp: October 29, 2016, 09:00:53 pm
content: Hi ALex, how are youBasically, my TCC0 needs to generate 64Khz continuosly in PA08 (Working well).Also, in same TCC0 I want to generate 64Khz no continuosly in PA09, because I want take same phase of PA08 (any delay in nano seconds between them is relevant to me)In PA09 I will supply 8 pulses in 64Khz in 16 times with 1ms delay between them .Regards

author: ataradov
author_rank: Super Contributor
timestamp: October 29, 2016, 09:23:25 pm
content: Well, PWM switches the output when COUNT reaches CC. So you need to configure CC the same way as CC.Now your main program must switch between PA09 being driven by the PORT and by the TCC at correct times. At 64 kHz it should be doable.So basically you will have something like this:Code:void wait_start(){uint32_t prev;do{prev = COUNT;} while (COUNT >= prev);}{PA9_out();PA9_clr();PA9_pmuxdis();for (int i = 0; i < 16; i++){wait_start();// here we are synchronized with the output of the TCCPA9_pmuxen();// wait 8 transitionsfor (int j = 0; j < 8; j++)wait_start();PA9_pmuxdis();delay(1ms);}

author: Franc
author_rank: Regular Contributor
timestamp: October 29, 2016, 10:18:28 pm
content: Hi Alex,Now my TCC0 is blocking my program. Pls see below.Code:void init_TCC0 (void){PM->APBCMASK.reg |= PM_APBCMASK_TCC0;// Enable peripheral clock for TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_TCC0_TCC1;// Disable the GCLKwhile ((GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN));// Enable TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID (TCC0_GCLK_ID) |// TCC0 & TCC1 share same GCLKGCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN (0);while (GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN);// Wait till enabled// TCC0->CTRLA.reg &= ~ (TCC_CTRLA_ENABLE);// Disable TCC0TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 | TCC_CTRLA_PRESCSYNC_GCLK;TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_MFRQ;// Normal PWM// Initialize count to 0TCC0->COUNT.reg = 0;// TCC0->PER.reg = 100;// Set periodTCC0->CC.reg = 21;// Atualiza a frequencia de saida. Atual 63khzTCC0->CC.reg = 21;// TCC0->WEXCTRL.bit.OTMX = 0x01;// Route CC0 to OTMX;// Enable the timerTCC0->CTRLA.bit.ENABLE = 1;while (TCC0->SYNCBUSY.bit.ENABLE) ;// Wait till timer enabledGPIO_dirOut(DRIVE_R);GPIO_pmuxen(DRIVE_R, PF_MUX_E);GPIO_dirOut(MODU_OUT);for (int i = 0; i < 16; i++){wait_start();// here we are synchronized with the output of the TCCGPIO_pmuxen(MODU_OUT, PF_MUX_E);// wait 8 transitionsfor (int j = 0; j < 8; j++){wait_start();GPIO_pmuxen(MODU_OUT, PF_MUX_E);ddDelay_ms(1);}}}void wait_start(){uint32_t prev;do{prev = TCC0->COUNT.reg;}while (TCC0->COUNT.reg >= prev);}

author: ataradov
author_rank: Super Contributor
timestamp: October 29, 2016, 10:26:27 pm
content: First of all, your code looks noting like my pseudocode.I don't know what your pmux macros/functions are doing, but you have too many of them. Note that I disable PMUX in the loop, not just enable it all th time.And you obviously need to debug. I gave you a general idea, not a final solution.

author: Franc
author_rank: Regular Contributor
timestamp: October 31, 2016, 11:37:22 pm
content: Today I tried to do my command 'FOR' but I don't know what happens.My FOR is correct, I tested in another C compiler for PC and worked well my debug , but in SAM do not respond as wished.It is very simple, just take 8 pulses from my TCC0 while pressing the botton 1 of OLED Board. And command FOR also simple.This compiler is strange or I do not yet understand the muxesCode:while (!GPIO_read (O_SW1)){for (int j = 0; j < 8; j++) // wait 8 transitions of mux 'E' to PA09{GPIO_pmuxen(MODU_OUT, PF_MUX_E); //MOD_OUT is PA09 .}GPIO_pmuxdis(MODU_OUT); // disable PA09ddDelay_ms(1); //wait 1 ms.}Regards!

author: ataradov
author_rank: Super Contributor
timestamp: October 31, 2016, 11:39:50 pm
content: Quote from: Franc on October 31, 2016, 11:37:22 pmThis code does not match the comment. It does not wait for anything and also does not make much sense, since after MUX is enabled once, consequtive enable requests do absolutely nothing.Please describe in human words what you want pins to do. Draw timing diagrams. I feel like you don't fully understand what you want yourself.

author: Franc
author_rank: Regular Contributor
timestamp: October 31, 2016, 11:53:58 pm
content: yes friend, this is my doubt for pin Mux. Maybe a new topic for Pin Mux of Sam D?It is very basic. I know I am confusebut I started few weeks ago with ARM.Only for test for me understand, I want to toggle the PA09 8 times with the Mux 'E' from my TCC0 that supplying a signal of 64Khz. After toggle 8 times, my software needs to wait 1ms. This routine is continuos while my Botton 1 is pressed (just to me understand)Regards!

author: ataradov
author_rank: Super Contributor
timestamp: October 31, 2016, 11:57:43 pm
content: Quote from: Franc on October 31, 2016, 11:53:58 pmLet's continue with this one.Quote from: Franc on October 31, 2016, 11:53:58 pmYou can't do this. The point of multiplexing is that only one peripheral controls the pin. If TCC controls it, then you can't do anything about it, it is under TCC control. All you can do is to read TCC state and try to guess what TCC is doing with the pin. Just as I've outlined in my code.PS:https://en.wikipedia.org/wiki/Multiplexer

author: Franc
author_rank: Regular Contributor
timestamp: November 01, 2016, 12:16:28 am
content: Same TCC0 supply 64Khz to other pin PA08 continuosly through mux E.QuoteSo, I cannot use a botton to start my test. But I tried direct without botton and no success. Sorry but I cannot act in the signal supplied to I/O from TCC? Is it?

author: ataradov
author_rank: Super Contributor
timestamp: November 01, 2016, 12:19:58 am
content: Quote from: Franc on November 01, 2016, 12:16:28 amSo?Quote from: Franc on November 01, 2016, 12:16:28 amWhat makes you think this? You can start the test using the button.The problem here is that what you want to do in the test can't be done.Quote from: Franc on November 01, 2016, 12:16:28 amNo, you can't, unless you externally loop it back to another pin. But this is not necessary, as you can predict what the pin state is based on the TCC registers, just like my code does.

author: Franc
author_rank: Regular Contributor
timestamp: November 01, 2016, 12:33:19 am
content: Sorry Alex, still confuse to me his code above. Is your 'COUNT' the count register of TCC0?In my understand you are manipulating the Mux similar I made above.Regards!Code:PA9_out();PA9_clr();PA9_pmuxdis()for (int i = 0; i < 16; i++){wait_start();// here we are synchronized with the output of the TCCPA9_pmuxen();// wait 8 transitionsfor (int j = 0; j < 8; j++)wait_start();PA9_pmuxdis()delay(1ms);

author: ataradov
author_rank: Super Contributor
timestamp: November 01, 2016, 12:38:36 am
content: Quote from: Franc on November 01, 2016, 12:33:19 amCorrect.Quote from: Franc on November 01, 2016, 12:33:19 amYour understanding is wrong.I enable the mux, so that TCC can drive the pin, then I call wait_start() 8 times, this waits until TCC changes the state 8 times, then I disable the mux, so that PORT peripheral drives the pin, which makes it go low, because I previously set output to 0 (PA9_clr()).The timer is still running and counting, it is just not in control of the pin anymore.This method gives you accurate timing, since it is derived from the hardware, byt you still have control over number of pulses, you just need to be fast enough to take the output from the timer when it is time, but at 64 kHz it should not be a big problem.

author: Franc
author_rank: Regular Contributor
timestamp: November 07, 2016, 10:19:45 pm
content: Hi friend! Today I returned to my project but still no success.My code below is blocking my program once I press the Button1.My issue is inwait_start()function. I really think it.Do you have any idea? Where I am missing?Code:b_btn1_state = !GPIO_read (O_SW1);while (!GPIO_read (O_SW1)) {GPIO_pmuxen(MODU_OUT, PF_MUX_E);//enable Mux Efor (int j = 0; j < 8; j++){wait_start();}GPIO_pmuxdis(MODU_OUT); // disable Mux EddDelay_ms(1);}void wait_start(){uint32_t prev;do{prev = TCC0->COUNT.reg;}while (TCC0->COUNT.reg >= prev);}

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 10:25:45 pm
content: Quote from: Franc on November 07, 2016, 10:19:45 pmYou need to use a debugger or any other way of debugging (UART prints, led blinking, anything really).I typed that function into the browser, I don't know why it may not work or block.I see no reason for this, sooner or later COUNT will be reset to 0 and and will be less than previous value.

author: Franc
author_rank: Regular Contributor
timestamp: November 07, 2016, 10:42:21 pm
content: Yes Alex, I am using my XplainedPro SamD21 and testing the output pins with my Oscilloscope. Also i have a Display OLED, when I press the button the Display is blocking.QuoteI think it. I don't like AS7, maybe any AS7 bug?

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 10:46:02 pm
content: Quote from: Franc on November 07, 2016, 10:42:21 pmAS7 is an IDE, it uses GCC as a compiler. And blaming the compiler is the last thing you should be doing here.You need to figure out why this function is blocking. Print the values of 'prev' and TCC0->COUNT.reg.What are your timer settings? For this to work well, you want to prescale the timer as much as possible, so your PER and CC values are as big as possible.

author: Franc
author_rank: Regular Contributor
timestamp: November 07, 2016, 10:52:28 pm
content: QuoteOkay ALex!QuoteSorry, I don't know how can I do that.My Prescaler is /16 for 48Mhz clock as below:Code:void init_drive_rod (void){PM->APBCMASK.reg |= PM_APBCMASK_TCC0;// Enable peripheral clock for TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_TCC0_TCC1;// Disable the GCLKwhile ((GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN));// Enable TCC0GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID (TCC0_GCLK_ID) |// TCC0 & TCC1 share same GCLKGCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN (0);while (GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN);// Wait till enabled// TCC0->CTRLA.reg &= ~ (TCC_CTRLA_ENABLE);// Disable TCC0TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 | TCC_CTRLA_PRESCSYNC_GCLK;TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_MFRQ;// Normal PWM// Initialize count to 0TCC0->COUNT.reg = 0;// TCC0->PER.reg = 100;// Set periodTCC0->CC.reg = 21;// Atualiza a frequencia de saida. Atual 63khzTCC0->CC.reg = 21;// TCC0->WEXCTRL.bit.OTMX = 0x01;// Route CC0 to OTMX;// Enable the timerTCC0->CTRLA.bit.ENABLE = 1;while (TCC0->SYNCBUSY.bit.ENABLE) ;// Wait till timer enabled}

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 10:57:13 pm
content: Quote from: Franc on November 07, 2016, 10:52:28 pmWell, you will have to learn. My starter projects have examples of debug UART output, you can use that code as a starter.Quote from: Franc on November 07, 2016, 10:52:28 pmYour code has PER setting commented out, so I have no idea how this thing is working in a first place.Also, increase your prescaler.

author: Lajon
author_rank: Contributor
timestamp: November 07, 2016, 10:58:12 pm
content: About reading COUNT, this register for TCC needs read sync.QuoteSo probably something like this before reading COUNTCode:while (TCC0->SYNCBUSY.bit.CTRLB);TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;while (TCC0->SYNCBUSY.bit.CTRLB);/Lars

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 11:02:02 pm
content: Quote from: Lajon on November 07, 2016, 10:58:12 pmIf both peripherals are clocked from the same clock source, then it does not matter all that much. And even if not, we are not interested in exact correct value, we just need to know if it crossed back to 0.

author: Lajon
author_rank: Contributor
timestamp: November 07, 2016, 11:04:40 pm
content: It will not change without the CMD write in my experience (also not when looking at it in the debugger)./Lars

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 11:05:34 pm
content: Quote from: Lajon on November 07, 2016, 11:04:40 pmYeah, it looks like it is the case. It worked fine with TC, but it looks like TCC needs mandatory synchronization.

author: Franc
author_rank: Regular Contributor
timestamp: November 07, 2016, 11:38:04 pm
content: Hi Lajon/Alex, thanks!I tried again but no success. When I press the Button, my software is blocking inwait_start()function, that is, only doing PA09 muxed continuosly, then my OLED blocks.QuoteI tested 64.QuoteI thought it is not necessary to use because I want only the CC[] match.Code:b_btn1_state = !GPIO_read (O_SW1);while (!GPIO_read (O_SW1)){GPIO_pmuxen(MODU_OUT, PF_MUX_E);//enable Mux Efor (int j = 0; j < 8; j++){wait_start();}GPIO_pmuxdis(MODU_OUT); // disable Mux EddDelay_ms(1);}void wait_start(){uint32_t prev;do{prev = TCC0->COUNT.reg;}while (TCC0->SYNCBUSY.bit.CTRLB);TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;while (TCC0->SYNCBUSY.bit.CTRLB);while (TCC0->COUNT.reg >= prev);}

author: ataradov
author_rank: Super Contributor
timestamp: November 07, 2016, 11:43:30 pm
content: Quote from: Franc on November 07, 2016, 11:38:04 pmYou've already got a thing to try with synchronization. It looks like it is necessary for TCC.Quote from: Franc on November 07, 2016, 11:38:04 pmHave you adjusted anything else to accommodate this change?Quote from: Franc on November 07, 2016, 11:38:04 pmWhat exactly should happen on CC[] match?PER defines PWM frequency, CC[] define duty cycle. Both are necessary for operation.Quote from: Franc on November 07, 2016, 11:38:04 pmYou need to do this inside the loop, not just some random place.You really need to pause on this project and just play with MCUs in general. You also need to learn how to use a real debugger. Your Xplained board comes with one, use it.This case is also a good example why you should not have messy code. Always enforce coding style. It pays in the long run.

author: Franc
author_rank: Regular Contributor
timestamp: November 14, 2016, 12:13:35 pm
content: QuoteDear Alex, that day it was my last try. I had tested in all ways. Including in loop.I am pretty right that my issue is in 'while (TCC0->COUNT.reg >= prev);' because the program blocks in'void wait_start()'function.QuoteI don't want stop, it is a very simple code. Remember this forum is for students also . These posts will help a lot of students as me in the future..Alex/Lajon, could I send my complete code to you check for help me? Really it does not work and I don´t have idea where I am wronging.Regards!

author: ataradov
author_rank: Super Contributor
timestamp: November 14, 2016, 04:50:59 pm
content: Quote from: Franc on November 14, 2016, 12:13:35 pmThere is no way for me to teach you how to debug the code remotely. Here is a start though. Write this code, after TCC initialization:Code:volatile int cnt;while (1){while (TCC0->SYNCBUSY.bit.CTRLB);TCC0->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;while (TCC0->SYNCBUSY.bit.CTRLB);cnt = TCC0->COUNT.reg;}Step thoguh it in the debugger, or print out the values of cnt. Don't move on to anything else until this loop prints non-zero numbers.