Turn on LED on SAMD20 in bootloader code

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

Hi,

 

I'm fairly new to SAMD20, so this is a very basic question:

 

I'm trying to turn on 3 LEDs in the booloader code in SAMD20 on a custom board. My LEDS are connected to PA19 - PA21. This is my code :

 

static void check_start_application(void)
{
        volatile PortGroup *led_port = (volatile PortGroup *)&PORT->Group[0];
        led_port->DIRSET.reg = (1<<19);
        led_port->OUTCLR.reg = (1<<19);
        led_port->OUTSET.reg = (1<<19);

        led_port->DIRSET.reg = (1<<20);
        led_port->OUTCLR.reg = (1<<20);
        led_port->OUTSET.reg = (1<<20);

        led_port->DIRSET.reg = (1<<21);
        led_port->OUTCLR.reg = (1<<21);
        led_port->OUTSET.reg = (1<<21);
}

 

Obviously I'm doing something wrong, but I just can't figure it out. Any pointers?

 

TIA

Yogi

This topic has a solution.
Last Edited: Sat. Oct 7, 2017 - 09:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are the LEDs active high or low?

Why are you clearing the bit and then setting it?

Why not something like (assuming active low and ignoring the led_port assignment):

PORT->Group[0].DIRSET.reg = (1<<19) | (1<<20) | (1<<21);
PORT->Group[0].OUTCLR.reg = (1<<19) | (1<<20) | (1<<21);

 

David (aka frog_jr)

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

frog_jr wrote:

Are the LEDs active high or low?

Why are you clearing the bit and then setting it?

Why not something like (assuming active low and ignoring the led_port assignment):

PORT->Group[0].DIRSET.reg = (1<<19) | (1<<20) | (1<<21);
PORT->Group[0].OUTCLR.reg = (1<<19) | (1<<20) | (1<<21);

 

 

They are active low. Clearing them then setting them was definitely wrong :-)

 

I tried out your suggestion but that did not work. I'm assuming that port A signals are in Group[0] and B in Group[1]. Is this assumption correct? Also, after we set the direction for a pin, do we have to write to the 'Write configuration' reg for it to take effect?

 

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

YogiWannabe wrote:
port A signals are in Group[0] and B in Group[1]
Correct.
YogiWannabe wrote:
do we have to write to the 'Write configuration' reg for it to take effect?
No, only if you are changing multiple pins to the same configuration (pullup, drive strength, input enable and/or peripheral multiplexer function). If you have not previously changed the peripheral function of these pins, this will not be necessary.

Prior to setting the GPIOs, how have you configured your clock selection and GCLK0?

David (aka frog_jr)

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

frog_jr wrote:

Prior to setting the GPIOs, how have you configured your clock selection and GCLK0?

void system_init()
{
        uint32_t temp_genctrl;

        /* Configure flash wait states */
        NVMCTRL->CTRLB.bit.RWS = FLASH_WAIT_STATES;

        /* Set OSC8M prescalar to divide by 1 */
        SYSCTRL->OSC8M.bit.PRESC = 0;

        /* Configure OSC8M as source for GCLK_GEN0 */
        GCLK_GENCTRL_Type genctrl = {0};
        GCLK->GENCTRL.bit.ID = 0; /* GENERATOR_ID - GCLK_GEN_0 */
        while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
        temp_genctrl = GCLK->GENCTRL.reg;
        genctrl.bit.SRC = GCLK_GENCTRL_SRC_OSC8M_Val;
        genctrl.bit.GENEN = true;
        genctrl.bit.RUNSTDBY = false;
        GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl);
        while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
}

This is the code to setup the clocks. Earlier the bootloader was calling system_init() after setting up the GPIO. I tried calling system_init() before setting up the GPIO but the LEDs still don't light up.

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

YogiWannabe wrote:
GCLK->GENCTRL.reg = (genctrl.reg | temp_genctrl);

Why are you ORing genctrl.reg with temp_genctrl?

Here is a simple LED blinker (written for D21, should work on D20):

#include "sam.h"

volatile uint32_t MS_Timer = 0;

void system_init() {

    SYSCTRL->OSC8M.bit.PRESC = 0;        // Set OSC8M prescaler to Divide-by-1

    // GENCTRL[0] is used for CPU clock (for GCLK_GENCTRL_DIV => 0 & 1 will both do Divide-by-1)
    GCLK->GENDIV.reg = GCLK_GENDIV_ID (0) | GCLK_GENDIV_DIV (1);

    // Enable GCLK generator 0, source = OSC8M, run in Standby
    GCLK->GENCTRL.reg = GCLK_GENCTRL_ID (0) | GCLK_GENCTRL_SRC (GCLK_SOURCE_OSC8M)
                        | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN;

    while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);    // Wait till synchronization is complete

    asm volatile ("cpsie i");            // Enable interrupts
}

void SysTick_Handler (void) {
    MS_Timer++;                    // Increment free-running millisecond timer
}

int main (void) {

    /* Initialize the SAM system */
    system_init();
    SysTick_Config (8000000 / 1000);    // Set SysTick for 1000 interrupts per second
    
    PORT->Group[1].DIRSET.reg = (1 << 3) | (1 << 2);    // LED1 & LED2 as outputs
    PORT->Group[1].OUTCLR.reg = (1 << 3);   // LED2 on
    PORT->Group[1].OUTSET.reg = (1 << 2);   // LED1 off

    uint32_t LED0_Time = 500;

    while (1) {
        if (MS_Timer >= LED0_Time) {
            LED0_Time += 500;
            PORT->Group[1].OUTTGL.reg = (1 << 3) | (1 << 2);    // Alternately blink the LEDs each second
        }
    }
}

Edit: unfortunately some of the whitespace was lost in trying to format this code...

WYSINWYG

David (aka frog_jr)

Last Edited: Fri. Oct 6, 2017 - 11:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the sample code, but the LEDs still don't blink.

 

The code that I'm working on is bootloader code that I got from github (https://github.com/Sweet-Peas/sa...).

 

 I'm cross compiling it on Linux and deploying it via Atmel studio. My board and LEDs work fine with Atmel studio Start project in my main app.

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

I finally got it working. All I had to do was use PORT_IOBUS at 0x60000000 instead of PORT @ 0x41004400. This is a bit confusing because the SAMD20 documentation shows that location 0x60000000 is undefined.