SAMB11 pin manipulations (third try to post)

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

How can this be so hard?

I'm just trying to toggle between pull-up and pull-down or input and output, but it's not working. Atmel Start/ASF4 based stupid test code.

 

Why is there nothing with PULL_DOWN. I get only 0.6 uA sink to pin, while it should be arounf 30 uA. With PULL_UP I do get 30 uA source, but I can't get that to stop with PULL_OFF.

When I have once set the direction OUT, I can't change it back to IN without reset.

 

Using ASF3 and "gpio_pin_set_config" etc. I can do all the toggling and get the LED to glow with PULL_DOWN. So there is nothing wrong in the chip and it's capable of doing all these changes.

 

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

Wow! I managed to get the post through "unpublished topic". Here is the code

 

 

 static uint16_t i=0;
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_OFF);
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_OFF);
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_IN);
  DBG_LOG("\nLED IN PULL_OFF"); // Nothing

  while(gpio_get_pin_level(BLE_APP_SW) || i++<1000);
  DBG_LOG("LED IN PULL_DOWN");
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_DOWN);
  while(!gpio_get_pin_level(BLE_APP_SW)); // Nothing

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++<1000);
  DBG_LOG("LED IN PULL_UP");
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_UP);
  while(!gpio_get_pin_level(BLE_APP_SW)); // Nothing

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED OUT LOW");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_OUT);
  gpio_set_pin_level(BLE_APP_LED, false);
  while(!gpio_get_pin_level(BLE_APP_SW)); // LED is ON

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED OUT HIGH");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_OUT);
  gpio_set_pin_level(BLE_APP_LED, true);
  while(!gpio_get_pin_level(BLE_APP_SW)); // Nothing

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED OUT LOW");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_OUT);
  gpio_set_pin_level(BLE_APP_LED, false);
  while(!gpio_get_pin_level(BLE_APP_SW)); // LED is ON

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED IN PULL_UP");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_IN);
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_UP);
  while(!gpio_get_pin_level(BLE_APP_SW)); // LED is ON

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED IN PULL_DOWN");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_IN);
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_DOWN);
  while(!gpio_get_pin_level(BLE_APP_SW)); //LED is ON

  i=0;
  while(gpio_get_pin_level(BLE_APP_SW) || i++>1000);
  DBG_LOG("LED IN PULL_DOWN, LEVEL UP");
  gpio_set_pin_direction(BLE_APP_LED, GPIO_DIRECTION_IN);
  gpio_set_pin_pull_mode(BLE_APP_LED, GPIO_PULL_DOWN);
  gpio_set_pin_level(BLE_APP_LED, true);
  while(!gpio_get_pin_level(BLE_APP_SW)); // Nothing
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Digging the ASF code it seems that setting direction IN ASF3 uses OUTENCLR register (sam0/drivers/gpio/gpio.c):

 if(config->direction == GPIO_PIN_DIR_INPUT) {
                                if(gpio_pin < 16) {
                                        GPIO0->OUTENCLR.reg = (1 << gpio_pin);


 

Later:

 

 

             } else if(config->direction == GPIO_PIN_DIR_OUTPUT) {
                                if (gpio_pin < 16) {
                                        GPIO0->OUTENSET.reg = (1 << gpio_pin);
         

While ASF4 uses OUTENSET also to set direction IN or OFF:

In hal/include/hal_gpio.h:

static inline void gpio_set_pin_direction(const uint8_t pin, const enum gpio_direction direction)
{
        _gpio_set_direction((enum gpio_port)GPIO_PORT(pin), 1U << GPIO_PIN(pin), direction);
}

 

In hpl/gpio/hpl_gpio_base.h

 

 

              case GPIO_DIRECTION_OFF:
                        if (mask_gpio1 == 0) {
                                hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
                        } else {
                                hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
                        }
                        break;

                case GPIO_DIRECTION_IN:
                        if (mask_gpio1 == 0) {
                                hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
                        } else {
                                hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
                        }
                        break;

                case GPIO_DIRECTION_OUT:
                        if (mask_gpio1 == 0) {
                                hri_gpio_set_OUTENSET_reg(GPIO0, mask);
                        } else {
                                hri_gpio_set_OUTENSET_reg(GPIO1, mask_gpio1);
                        }
                        break;


And finally in hri/hri_gpio_b11.h

static inline void hri_gpio_set_OUTENSET_reg(const void *const hw, hri_gpio_outenset_reg_t mask)
{
        GPIO_CRITICAL_SECTION_ENTER();
        ((Gpio *)hw)->OUTENSET.reg |= mask;
        GPIO_CRITICAL_SECTION_LEAVE();
}


static inline void hri_gpio_clear_OUTENSET_reg(const void *const hw, hri_gpio_outenset_reg_t mask)
{
        GPIO_CRITICAL_SECTION_ENTER();
        ((Gpio *)hw)->OUTENSET.reg &= ~mask;
        GPIO_CRITICAL_SECTION_LEAVE();
}

 

So is this a bug in Atmel Start/ASF4? There is no decent datasheet for SAMB11 so I have no idea can OUTENSET be cleared or is OUTENCLR the proper way to clear it. Seems like OUTENSET can't be cleared.

 

There is also

static inline void hri_gpio_set_OUTENCLR_reg(const void *const hw, hri_gpio_outenclr_reg_t mask)
{
        GPIO_CRITICAL_SECTION_ENTER();
        ((Gpio *)hw)->OUTENCLR.reg |= mask;
        GPIO_CRITICAL_SECTION_LEAVE();
}

 

In the same file, but it is not used.

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

I was wrong about ASF3, it doesn't work either regarding PULL_UP/DOWN. You can't toggle with PULL_UP and PULL_DOWN using "gpio_pin_set_config". Or you can, but once you have set PULL_UP you need to set first PULL_NONE and then PULL_DOWN. Otherwise the pin will remain in PULL_UP.

ASF3:

 

   switch(config->input_pull) {
                        case GPIO_PIN_PULL_NONE:
                            LPMCU_MISC_REGS0->PULL_ENABLE.reg |= (1 << gpio_pin);
                            break;
                        case GPIO_PIN_PULL_UP:
                            LPMCU_MISC_REGS0->PULL_ENABLE.reg &= ~(1 << gpio_pin);
                            break;
                        case GPIO_PIN_PULL_DOWN:
                            /* Set R-Type */
                            LPMCU_MISC_REGS0->RTYPE_PAD_0.reg |= (1 << gpio_pin);
                            /* Set REN */
                            LPMCU_MISC_REGS0->PULL_ENABLE.reg &= ~(1 << gpio_pin);
                            break;



ASF4:

 

 

       switch (pull_mode) {
        case GPIO_PULL_OFF:
                hri_lpmcumiscregsmiscregs_set_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
                break;

        case GPIO_PULL_UP:
                hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
                hri_lpmcumiscregsmiscregs_clear_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0, pin_num);
                break;

        case GPIO_PULL_DOWN:
                hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
                hri_lpmcumiscregsmiscregs_set_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0, pin_num);
                break;



static inline void hri_lpmcumiscregsmiscregs_set_PULL_ENABLE_reg(const void *const                     hw,
                                                                 hri_lpmcu_misc_regs_pull_enable_reg_t mask)
{
        LPMCU_MISC_REGS_CRITICAL_SECTION_ENTER();
        ((LpmcuMiscRegs *)hw)->PULL_ENABLE.reg |= mask;
        LPMCU_MISC_REGS_CRITICAL_SECTION_LEAVE();
}


static inline void hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(const void *const                     hw,
                                                                   hri_lpmcu_misc_regs_pull_enable_reg_t mask)
{
        LPMCU_MISC_REGS_CRITICAL_SECTION_ENTER();
        ((LpmcuMiscRegs *)hw)->PULL_ENABLE.reg &= ~mask;
        LPMCU_MISC_REGS_CRITICAL_SECTION_LEAVE();
}


static inline void hri_lpmcumiscregsmiscregs_set_RTYPE_PAD_0_reg(const void *const                     hw,
                                                                 hri_lpmcu_misc_regs_rtype_pad_0_reg_t mask)
{
        LPMCU_MISC_REGS_CRITICAL_SECTION_ENTER();
        ((LpmcuMiscRegs *)hw)->RTYPE_PAD_0.reg |= mask;
        LPMCU_MISC_REGS_CRITICAL_SECTION_LEAVE();
}


static inline void hri_lpmcumiscregsmiscregs_clear_RTYPE_PAD_0_reg(const void *const                     hw,
                                                                   hri_lpmcu_misc_regs_rtype_pad_0_reg_t mask)
{
        LPMCU_MISC_REGS_CRITICAL_SECTION_ENTER();
        ((LpmcuMiscRegs *)hw)->RTYPE_PAD_0.reg &= ~mask;
        LPMCU_MISC_REGS_CRITICAL_SECTION_LEAVE();
}


So what's the difference here? RTYPE is not cleared for pull-up in ASF3 and for pull-down RTYPE/PULL_ENABLE are done in different order.

 

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

OK. The bugs are found now. For ASF4 in hpl/gpio/hpl_gpio_base.h (generated by Atmel Start for SAMB11 Xplained Pro). The original buggy code set as comments. SERIOUSLY? Is this the quality of ASF? Totally untested for this part even for basic IO manipulation!

 

    if (port == GPIO_PORTA) {
        switch (direction) {
        case GPIO_DIRECTION_OFF:
            if (mask_gpio1 == 0) {
              //hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
              hri_gpio_set_OUTENCLR_reg(GPIO0, mask);
            } else {
              //hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
              hri_gpio_set_OUTENCLR_reg(GPIO1, mask_gpio1);
            }
            break;

        case GPIO_DIRECTION_IN:
            if (mask_gpio1 == 0) {
              //hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
              hri_gpio_set_OUTENCLR_reg(GPIO0, mask);
            } else {
              //hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
              hri_gpio_set_OUTENCLR_reg(GPIO1, mask_gpio1);
            }
            break;



    switch (pull_mode) {
    case GPIO_PULL_OFF:
      //hri_lpmcumiscregsmiscregs_set_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
      hri_lpmcumiscregsmiscregs_set_PULL_ENABLE_reg(LPMCU_MISC_REGS0,(1<< pin_num));
        break;

    case GPIO_PULL_UP:
      //hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
      //hri_lpmcumiscregsmiscregs_clear_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0, pin_num);
      hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0,(1<< pin_num));
      hri_lpmcumiscregsmiscregs_clear_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0,(1<< pin_num));
    break;

    case GPIO_PULL_DOWN:
      //hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0, pin_num);
      //hri_lpmcumiscregsmiscregs_set_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0, pin_num);
      hri_lpmcumiscregsmiscregs_set_RTYPE_PAD_0_reg(LPMCU_MISC_REGS0, (1<< pin_num));
      hri_lpmcumiscregsmiscregs_clear_PULL_ENABLE_reg(LPMCU_MISC_REGS0, (1<< pin_num));
        break;


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

jmaja1 wrote:

OK. The bugs are found now. For ASF4 in hpl/gpio/hpl_gpio_base.h (generated by Atmel Start for SAMB11 Xplained Pro). The original buggy code set as comments. SERIOUSLY? Is this the quality of ASF? Totally untested for this part even for basic IO manipulation!

 

    if (port == GPIO_PORTA) {
        switch (direction) {
        case GPIO_DIRECTION_OFF:
            if (mask_gpio1 == 0) {
              //hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
              hri_gpio_set_OUTENCLR_reg(GPIO0, mask);
            } else {
              //hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
              hri_gpio_set_OUTENCLR_reg(GPIO1, mask_gpio1);
            }
            break;

        case GPIO_DIRECTION_IN:
            if (mask_gpio1 == 0) {
              //hri_gpio_clear_OUTENSET_reg(GPIO0, mask);
              hri_gpio_set_OUTENCLR_reg(GPIO0, mask);
            } else {
              //hri_gpio_clear_OUTENSET_reg(GPIO1, mask_gpio1);
              hri_gpio_set_OUTENCLR_reg(GPIO1, mask_gpio1);
            }
            break;


 

What is the correct setting for output according to you ?