Author Topic: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM  (Read 4128 times)

0 Members and 1 Guest are viewing this topic.

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« on: December 14, 2015, 10:32:21 pm »
Hello all,

I am a tad stuck with trying to generate a PWM output on the ATSAM4S chip.

for some reason I am getting no output at all. I may be missing something as I have not had much experience with ARM at all.

What I am trying to accomplish is to generate the outputs needed for a full-bridge transformer driver, I also need to add dead-time.

I have been reading through the manuals for ages, I cannot find anything that helps and along with that I have no clue on how to go about fault finding on the ARM system without any proper experience, guides or advice.

Here is my code:

Code: [Select]
#include <asf.h>

int main (void)
{
/* Insert system clock initialization code here (sysclk_init()). */
sysclk_init();
board_init();

pwm_channel_t pwm_channel_instance;

pwm_channel_disable(PWM, PWM_CHANNEL_0);

pwm_clock_t clock_setting = {
.ul_clka = 1000 * 100,
.ul_clkb = 0,
.ul_mck = 48000000
};
pwm_init(PWM, &clock_setting);
pwm_channel_instance.ul_prescaler = PWM_CMR_CPRE_CLKA;
pwm_channel_instance.ul_period = 100;
pwm_channel_instance.ul_duty = 50;
pwm_channel_instance.channel = PWM_CHANNEL_0;
pwm_channel_init(PWM, &pwm_channel_instance);


pio_configure_pin(PIO_PA19B_PWML0, PIO_PERIPH_B);
ioport_disable_pin(PIO_PA19B_PWML0);


pmc_enable_periph_clk(ID_PWM);

pwm_channel_enable(PWM, PWM_CHANNEL_0);



while(1);

}

I would really appreciate any and all advice and help given.

 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #1 on: December 15, 2015, 06:31:39 am »
PWM library for that chip sucks. It will end up compiling to large and inefficient code even with high degree of optimization. The abstraciton layer is not convenient and is coded badly. ATMEL libs for ARM chips suck bigtime (almost the same level as STM32 CubeMX)

Manipulate registers directly as advised by datasheet and you'll be fine.
I love the smell of FR4 in the morning!
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #2 on: December 15, 2015, 07:56:34 am »
PWM library for that chip sucks. It will end up compiling to large and inefficient code even with high degree of optimization. The abstraciton layer is not convenient and is coded badly. ATMEL libs for ARM chips suck bigtime (almost the same level as STM32 CubeMX)

Manipulate registers directly as advised by datasheet and you'll be fine.

Problem is there is so much in there I have no clue what needs to be done to get it started and going. I'm sure you understand having only used AVR before it's a major leap.
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #3 on: December 15, 2015, 08:13:58 am »
Your first problem is that you are enabling clock at the end. This should not be understood as clocking the PWM counter, but clocking the module at all. No clock = no effect. In general when a module which is not clocked is written to or read from the chip should either do nothing or raise some sort of fault. SAM4 does the former (no effect).  First thing you do in order to communicate with any peripheral in ARM powered microcontrollers is usually to enable power/clock to that module.

So the line:
Code: [Select]
pmc_enable_periph_clk(ID_PWM);should be the first one, as all previous lines do nothing.

In general PWM config in SAM goes like this:
-configure gpio. Make sure that 'GPIO' bits are off, you want it to be peripheral output, not GPIO. Assign correct  peripheral to that pin (letters from A to D)
-using syntax like this:
Code: [Select]
PWM->PWM_CH_NUM[channel_number_here].[perticular_register]for example
Quote
PWM->PWM_CH_NUM[0].PWM_CMR = something

There are 4 registers for every PWM channel
PWM_CMR - mode register - sets clocking, data alignment and other stuff like that
PWM_CPRD - pwm period
PWM_CDTY - duty cycle register (mus be smaller than SPRD or PWM won't work
PWM_DT - dead time - useful when using PWM to generate complementary outputs driving a half-bridge power stage


there are also general registers which are shared between all channels:
PWM_FPE - fault detection - cam be set to 0 in order to disable this
PWM_SCM - channel sync registers, advanced stuff that you can find out on your own
PWM_DIS / PWM_EN - enable, disable channels
PWM_IFR1/IDR1/IER1/IFR2/IER2/IDR2 - interrupt control
PWM_CLK - more clock control
I love the smell of FR4 in the morning!
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #4 on: December 15, 2015, 03:58:13 pm »
Your first problem is that you are enabling clock at the end. This should not be understood as clocking the PWM counter, but clocking the module at all. No clock = no effect. In general when a module which is not clocked is written to or read from the chip should either do nothing or raise some sort of fault. SAM4 does the former (no effect).  First thing you do in order to communicate with any peripheral in ARM powered microcontrollers is usually to enable power/clock to that module.

So the line:
Code: [Select]
pmc_enable_periph_clk(ID_PWM);should be the first one, as all previous lines do nothing.

In general PWM config in SAM goes like this:
-configure gpio. Make sure that 'GPIO' bits are off, you want it to be peripheral output, not GPIO. Assign correct  peripheral to that pin (letters from A to D)
-using syntax like this:
Code: [Select]
PWM->PWM_CH_NUM[channel_number_here].[perticular_register]for example
Quote
PWM->PWM_CH_NUM[0].PWM_CMR = something

There are 4 registers for every PWM channel
PWM_CMR - mode register - sets clocking, data alignment and other stuff like that
PWM_CPRD - pwm period
PWM_CDTY - duty cycle register (mus be smaller than SPRD or PWM won't work
PWM_DT - dead time - useful when using PWM to generate complementary outputs driving a half-bridge power stage


there are also general registers which are shared between all channels:
PWM_FPE - fault detection - cam be set to 0 in order to disable this
PWM_SCM - channel sync registers, advanced stuff that you can find out on your own
PWM_DIS / PWM_EN - enable, disable channels
PWM_IFR1/IDR1/IER1/IFR2/IER2/IDR2 - interrupt control
PWM_CLK - more clock control


Thanks for the information, I have redone my code to look like this:

Code: [Select]
#include <asf.h>

int main (void)
{
/* Insert system clock initialization code here (sysclk_init()). */
sysclk_init();
board_init();


pmc_enable_periph_clk(ID_PWM);



PWM->PWM_DIS = (1 << PWM_CHANNEL_0);
PWM->PWM_CH_NUM[0].PWM_CMR = (PWM_CMR_CPRE_CLKA & 0xF) | (PWM_CMR_CALG);
PWM->PWM_CH_NUM[0].PWM_CDTY = 50;
PWM->PWM_CH_NUM[0].PWM_CPRD = 100;
PWM->PWM_ENA = (1 << PWM_CHANNEL_0);


pio_configure_pin(PIO_PA19B_PWML0, PIO_PERIPH_B);
ioport_disable_pin(PIO_PA19B_PWML0);

pio_configure_pin(PIO_PA11B_PWMH0, PIO_PERIPH_B);
ioport_disable_pin(PIO_PA11B_PWMH0);


while(1);

}

However I am still getting nothing out. Am I missing something?
Do you also have any recommended readings that helped you?


EDIT:

At last, something worked! seemed PIO wasn't working:
Code: [Select]
#include <asf.h>

int main (void)
{
/* Insert system clock initialization code here (sysclk_init()). */
sysclk_init();
board_init();

PIOA->PIO_PER=0x00000000;
PIOA->PIO_PDR=PIO_PA11B_PWMH0; // enable PWM
PIOA->PIO_IER=0x00000000; // disable interrupts
PIOA->PIO_IDR=0xFFFFFFFF;
PIOA->PIO_ABCDSR[0]= PIO_PA11B_PWMH0; // assign pin to peripheral B

pmc_enable_periph_clk(ID_PWM);

PWM->PWM_CH_NUM[0].PWM_CMR = (PWM_CMR_CPRE_MCK & 0xF);

PWM->PWM_CH_NUM[0].PWM_CPRD = 100;

PWM->PWM_CH_NUM[0].PWM_CDTY = 50;

PWM->PWM_ENA = (1 << PWM_CHANNEL_0);



//ioport_disable_pin(PIO_PA19B_PWML0);
//pio_configure_pin(PIO_PA19B_PWML0, PIO_PERIPH_B);

//ioport_disable_pin(PIO_PA11B_PWMH0);
//pio_configure_pin(PIO_PA11B_PWMH0, PIO_PERIPH_B);



while(1);

}

Thankfully some people with the Arduino Due had been doing similar stuff and I managed to come across it googling bits of your code. Huge thanks!
« Last Edit: December 15, 2015, 05:38:11 pm by TCWilliamson »
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #5 on: December 15, 2015, 06:46:33 pm »
O was gonna write that you also need to enable clock to the pip peripheral in order to set it up properly.

Sent from my HTC One M8s using Tapatalk.

I love the smell of FR4 in the morning!
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #6 on: December 15, 2015, 10:01:10 pm »
O was gonna write that you also need to enable clock to the pip peripheral in order to set it up properly.

Sent from my HTC One M8s using Tapatalk.

currently trying to integrate dead time and failing. I believe I disabled the protection, however I don't know how to check registers and that 'memory' thing you can access during debugging doesn't add up.. (32 hex bytes across not bits?)

Code: [Select]
#include <asf.h>

int main (void)
{
/* Insert system clock initialization code here (sysclk_init()). */
sysclk_init();
board_init();

PIOA->PIO_PER = 0;
PIOA->PIO_PDR = PIO_PA11B_PWMH0 | PIO_PA19B_PWML0; // enable PWM
PIOA->PIO_IER = 0; // disable interrupts
PIOA->PIO_IDR = 0xFFFFFFFF;
PIOA->PIO_ABCDSR[0] = PIO_PA11B_PWMH0 | PIO_PA19B_PWML0; // assign pin to peripheral B

pmc_enable_periph_clk(ID_PWM);

PWM->PWM_WPCR = PWM_WPCR_WPKEY_PASSWD | (PWM_WPCR_WPRG4 << 2) | PWM_WPCR_WPCMD_DISABLE_SW_PROT;



int32_t deadtime = 100; // set deadtime
int32_t width = 1000;
int32_t duty = 500;
// equal deadtime

PWM->PWM_CH_NUM[0].PWM_CMR = (PWM_CMR_CPRE_MCK_DIV_8 & 0xF);

PWM->PWM_CH_NUM[0].PWM_CPRD = width;

PWM->PWM_CH_NUM[0].PWM_CDTY = duty;

PWM->PWM_CH_NUM[0].PWM_DT = deadtime | ((duty-deadtime)<<15);

PWM->PWM_ENA = (1 << PWM_CHANNEL_0);

while(1);

}

Have you got any advice on this?

EDIT: nevermind, figured it out. Forgot to enable it on the PWM_CMR
« Last Edit: December 15, 2015, 10:20:26 pm by TCWilliamson »
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: ATSAM4SD32C | SAM4S-EK2 dev board | Unable to generate PWM
« Reply #7 on: December 16, 2015, 07:37:04 am »
Check the registers pertinent to PWM fault detection. If not handled correctly (and I dunno what the correct way is to be honest) but enabled (by default) if fault is detected the PWM is stopped until the fault is reset. Disable the fault detection system.
I love the smell of FR4 in the morning!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf