Mind = Blown - 64 PortPins and only 32 configuration registers?

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

I'll apologize ahead of time for this long-winded post.

 

What I need to accomplish:

1. I need to PWM PB12 (PIN 25 according to the datasheet)

 

Hardware and software in use:

1. SAMD21J18A Xplained pro dev board

2. WINC1500 SSL example program (this runs and is working as desired)

 

What I understand:

Having read the datasheet and chased down as many dependencies as I could find, it seems I need to set the MUXEN bit associated with PORTB12 (physical pin 25 according to the datasheet) and map the pin to the peripheral function E as defined by the datasheet.  I then need to set the period and duty-cycle and start the timer.  Sounds simple enough, but I've run into some trouble understanding the hardware.  The pin configuration registers start at address 0x40 and offset by the pin number. The pin I'm after is 25 making my target register address 0x59 (PINCFG25).  Mapping the PIN to the required mux required me to identify if it is even or odd and add the value to the associated PMUX register.  These registers start at address 0x30 + n*0x01

where n = 0:15.

 

Why I'm confused:

There are 64 port pins and only 32 configuration (PINCFG) registers. at the same time, there are 32 registers worth of PORTPINS for the PMUX registers but only 15 of them.  I can't seem to figure out how to configure these registers given the possibility for duplicate resources.  I've tried chasing this information down within the ASF PWM example, but it's written like a Russian nesting doll and I've been unable to locate the hardware layer abstraction (at least anything I would recognize).

 

What I'm asking for

A process I can use to setup PWM on PORTB12 (physical pin 25) and clarification on how the PINCFG and PMUX registers are supposed to be used.  How do I identify the correct PINCFG and PMUX registers for the physical pin I want to use.  Again, the MCU in use is the SAMD21J18A on the Xplained Pro board.

 

Thank you ahead of time for the help, Honestly, I had an easier time writing the MQTT client than I am trying to figure out this HAL.

This topic has a solution.
Last Edited: Sat. Aug 11, 2018 - 12:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, "up to 32 Pin Configuration registers" ... "in each group". PORTA is group #0, PORTB is group #1.

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

Thank you for the reply.  I had noticed that description in the datasheet.  However, this does not resolve the question of how to differentiate pins as there are only 32/16 registers for configuration and no settings in those registers to differentiate GroupA from GroupB.  If for the PMUX registers "n denotes the number of the set of I/O lines" how do I find out what that number is.  There appear to not be enough registers to represent all possible PortPins.  Is the documentation incomplete?

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

Let's see. You need to configure PB12.
PINGFG for PB12 is:
PORT->Group[1].PINCFG[12].reg
PMUX is a bit more confusing:
PORT->Group[1].PMUX[12/2].bit.PMUXE

 

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

Thank you for the response.  I'll try this.

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

OK, so I've spent the last few days trying to figure out how to get PWM working on PORTB12, but I've had no success.  My desire is to control period and duty-cycle but I'm not even entering the event handler.  Any idea where I'm going wrong here?

 

Here is what I have so far:

#include "sam.h"

#define LED0 PORT_PB12;

void init_TCC0();
void enable_interrupts();


int main(void)
{
	SystemInit(); // Initialize the SAM system

	init_TCC0();
	enable_interrupts();

	
	while (1)
	{
		
	}
}


void init_TCC0()
{
	//Map PB12 to Peripheral F (TCC0/WO6)
	PORT->Group[1].PINCFG[12].reg = 0x1;
	PORT->Group[1].PMUX[12/2].bit.PMUXE = 0x5;

	/* Configure TCC0 as a timer to blink LED0 */
	// Configure Clocks
	REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK6 | GCLK_CLKCTRL_ID_TCC0_TCC1;
	REG_PM_APBCMASK |= PM_APBCMASK_TCC0; // Enable TCC0 bus clock
	
	// Configure TCC0 (16 bit counter by default)
	TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV16;

	//Zero Count
	TCC0->COUNT.reg = 0;
	//Configure Period and duty-cycle
	TCC0->PER.reg = 1000;
	TCC0->CC->reg = 500;
	
	// Enable interrupts
	TCC0->INTENSET.reg |= TCC_INTENSET_OVF | TCC_INTENSET_ERR | TCC_INTENSET_MC0;
	
	// Enable TCC0
	TCC0->CTRLA.reg |= TCC_CTRLA_ENABLE;
}


void TCC0_Handler()
{
		REG_PORT_OUTTGL1 = LED0;
}


void enable_interrupts()
{
	NVIC_EnableIRQ( TCC0_IRQn );
}

 

Last Edited: Fri. Aug 10, 2018 - 08:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tcucore wrote:
This is my first time working with ARM

Note that this has nothing specifically to do with ARM 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Care to elaborate?  I'd love to know where I'm being tripped up.

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

The peripherals are entirely Atmel's own proprietary thing - they could equally well be used with any other CPU core.

 

In fact, many of the SAMD peripherals are the same as AVR32.

 

If you look at ARM-based controllers from other manufacturers, you will see that they do things differently...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the clarification.  I clearly don't understand where ARM ends and peripherals begin.  I think it's how the peripherals are set up that is tripping me up.  any chance of a crash course in setting up PWM for this MCU.  The best I've been able to do is modify an example I found to blink the LED, but I was unable to get control of duty-cycle.  The code I posted above was my attempt at getting what I wanted.  It does not work.

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

SystemInit() - what does that one do?
GCLK_CLKCTRL_GEN_GCLK6 - where do you enable GLCK6?
TCC0->CC->reg - does that compile? I thought CC was an array?

 

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

tcucore wrote:
any chance of a crash course in setting up PWM for this MCU. 

Have you studied the chip datasheet? That is where the peripheral operation is described.

 

And the ASF documentation?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  • @ezharkov  Thank you for the response.

 

SystemInit() - what does that one do? 

  • SystemInit() came from an example I am trying to work from and sets the core clock to 1Mhz

 

GCLK_CLKCTRL_GEN_GCLK6 - where do you enable GLCK6?    

  • REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK6 | GCLK_CLKCTRL_ID_TCC0_TCC1; 
    • I thought GCLK_CLKCTRL_CLKEN enabled the clock

 

TCC0->CC->reg - does that compile? I thought CC was an array?  

  • This does compile, but I looked back at it and found it is a union of 4 structures (which could be accessed as an array).  Thanks for pointing that out. 
  • I've revised the line to TCC0->CC->bit.CC = 500;   Code still compiles but I'm still not entering the interrupt.

 

 

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

I'm not using ASF.  I have had the datasheet open for 3 days.  I'm having a hard time working with it as there is some ambiguity in how it uses the term PIN.  The change-log notes a change in that PIN was now used to reference PAD as well. The referenced #defines are often not functional.  I understand this should be a trivial task.  I've done PWM before but this is not set up in the same way.  The HAL provided is more complex than anything I've dealt with, and I'm not used to working in C++.   I understand how PWM is supposed to work, I just can't seem to sort out the dependencies and software interfaces for this chip.

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

In your REG_GCLK_CLKCTRL assignment you select GCLK6 as a clock for TCC0.

Therefore, you need to enable GCLK6 itself first, something like:
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(6) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN;

But you probably don't need GCLK6 in the first place. Just use GCLK0 instead:
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC0_TCC1;

TCC0->CC->reg - never mind. I got confused myself. I understand why it compiles. But I would change it to TCC0->CC[0].reg to make it clear which of the 4 CC registers you want.

Speaking of WO[6] ... I don't know how one would drive that output. That must that Waveform Extension stuff. I've never used that stuff. To start with, I would pick on a WO[x] with an x within the 0-3 range, so that you could use a basic configuration with a matching CC[x].

If you really want PWM on PB12, I would use TC4/WO[0] instead.

 

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

tcucore wrote:
I'm not using ASF.

Perhaps you should - the whole point of ASF is to take care of this complexity for you.

 

The referenced #defines are often not functional.

Possibly because they assume you are using ASF?

 

I'm not used to working in C++

ASF is 'C' - not C++

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

I agree with awneil, why not try ASF, you can at least look at resulting register settings in the debugger.

 

Concerning the current code you have to think about what you intend for the PWM.

* software generated: use the interrupt and toggle like now but the port pin should be an output and you have to clear the interrupt flag (read about the INTFLAG register).

* hardware PWM: no interrupt needed and the pin configured as now for Peripheral F. Set a PWM mode (like NPWM) in the WAVE register. TCC0->CC[2] will be the duty cycle setting for reasons I attempted to explain here:

https://community.atmel.com/comm...

/Lars

Last Edited: Fri. Aug 10, 2018 - 10:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Lajon.  I was able to get it working with CC[2], but I'm having a difficult time understanding the statement in the post you linked to quoting the datasheet 

 

Configuration 0x0 is the default configuration. The channel location is the default one, and channels
are distributed on outputs modulo the number of channels. Channel 0 is routed to the Output matrix
output OTMX[0], and Channel 1 to OTMX[1]. If there are more outputs than channels, then channel
0 is duplicated to the Output matrix output OTMX[CC_NUM], channel 1 to OTMX[CC_NUM+1] and
so on.

 

The way I understand it for my configuration, I'm using PB12 which is connected to TCC0/WO[6] (Peripheral F) according to the datasheet.  and the physical pin number is 25.  You were able to figure out that I needed to use CC[2], but I can't figure out how you got there with this information.

 

Any chance I can get you to walk me through this?

Last Edited: Sat. Aug 11, 2018 - 12:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I'm not Lajon, but I'll try.
TCC0 has 4 channels (CC_NUM) and 8 outputs WO[0] - WO[7]
The first 4 outputs are straightforward:
    for WO[0] use channel CC[0]
    for WO[1] use channel CC[1]
    for WO[2] use channel CC[2]
    for WO[3] use channel CC[3]
Now we have no more channel; so we start with channel 0 again:
    for WO[4] use channel CC[0]
    for WO[5] use channel CC[1]
    for WO[6] use channel CC[2]
    for WO[7] use channel CC[3]

 

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

@ezharkov

 

Well...  That's deceptively simple.  Thank you!  This should be added to the datasheet.  Much more succinct.

 

Thank you all for your patience and help.  I learned a lot and appreciate you guys spending your time working through the ignorance of people like me.