Author Topic: ATSAMD10D13AS GPIO pin settings  (Read 908 times)

0 Members and 1 Guest are viewing this topic.

Offline WILDERNESSBAGELTopic starter

  • Contributor
  • Posts: 28
  • Country: hr
ATSAMD10D13AS GPIO pin settings
« on: March 09, 2022, 08:35:29 am »
I need some help to understand why my PINs aren't getting set to HIGH and LOW properly. As the title says I'm using ATSAMD10D13AS https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42242-SAM-D10_Datasheet.pdf#page=387. First I set the pin directions as OUTPUT and clear them in other words I want to set them to LOW and leave them in this state for 10s. Then I want to change all pins to act as inputs. After that I want to once again set pins as outputs and set some of them to HIGH and leave others to act as inputs once again for 10s. And finally I want to set all pins to inputs.

Code: [Select]

struct pinSettings{

    uint8_t number[10] = {0b01111101, 0b00000101, 0b01011011, 0b01001111, 0b00100111, 0b01101110, 0b01111110, 0b01000101, 0b01111111, 0b01101111};
    uint8_t segmentPinOrder[7] = {5, 6, 7, 8, 9, 14, 15};
    uint8_t clear = 0x00;
   
}pinsettings;

bool toggleNumber(uint8_t numberToDisplay){
    // PWM used to drive the display it doesn't use any of the pins below
    myPWM.begin();
    numberToDisplay = pinsettings.number[numberToDisplay];

for (uint8_t i = 0; i < 7; ++i) {
                // set all pins as outputs and set them to LOW
REG_PORT_DIR0 |= (1 << pinsettings.segmentPinOrder[i]);
REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder[i]);
REG_PORT_OUTCLR0 |= (1 << pinsettings.segmentPinOrder[i]);
}

myPWM.setOnPercent(45);

DelayMs(10000);
        // st all pins as inputs
REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);

    for (uint8_t i = 0; i < 7; ++i) {
        if ((numberToDisplay >> i) & 1) {
// set some of the pins as outputs and make them HIGH
REG_PORT_DIR0 |= (1 << pinsettings.segmentPinOrder[i]);
REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder[i]);
REG_PORT_OUTSET0 |= (1 << pinsettings.segmentPinOrder[i]);
        }
    }
    // PWM = 55 to turn the display ON (45 OFF)
    myPWM.setOnPercent(55);
    DelayMs(10000);

    // set all pins to inputs
    REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);

    return true;
}

If I comment out setting the pins to INPUTs everything seems to work ok but if I change them to inputs then it seems like I don't set them to outputs correctly.


EDIT: Ok if I got this correctly REG_PORT_DIRSET0 also sets the DIRTGL register which reverses the I/O direction of the pin, so I shoudn't use REG_PORT_DIR0 before REG_PORT_DIRSET0, is this correct?
« Last Edit: March 09, 2022, 09:08:57 am by WILDERNESSBAGEL »
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 854
Re: ATSAMD10D13AS GPIO pin settings
« Reply #1 on: March 09, 2022, 11:13:10 am »
Without looking too close, your use of CLR/SET registers is or will be a problem-

REG_PORT_DIRSET0 |=

These type of registers are designed for atomic needs, which use assignment only (writing 0 to a bit has no effect). The use of |= will end up reading the register first, and will then include using those values to set bits, bits that should be left alone.
 

Offline WILDERNESSBAGELTopic starter

  • Contributor
  • Posts: 28
  • Country: hr
Re: ATSAMD10D13AS GPIO pin settings
« Reply #2 on: March 09, 2022, 11:49:34 am »
Thanks I didn't realize that |= can act weirdly when using atomic registers. So if I understand correctly setting the register to some value should work? I tried doing the folowing
Code: [Select]
bool toggleNumber(uint8_t numberToDisplay){
    myPWM.begin();
    numberToDisplay = pinsettings.number[numberToDisplay];

uint32_t pinDirections = 0x00, pinState = 0x00;
// set all pins to LOW
for (uint8_t i = 0; i < 7; ++i) {
pinDirections |= (1 << pinsettings.segmentPinOrder[i]);
pinState |= (1 << pinsettings.segmentPinOrder[i]);
//REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder[i]);
//REG_PORT_OUTCLR0 |= (1 << pinsettings.segmentPinOrder[i]);
}
// assign the registers to new values
REG_PORT_DIRSET0 = pinDirections;
REG_PORT_OUTCLR0 = pinState;

myPWM.setOnPercent(45);

DelayMs(10000);
pinDirections = 0x00;
pinState = 0x00;
//REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);
        // NOW USING DIRCLR to set pins to input state
REG_PORT_DIRCLR0 = (PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);

    for (uint8_t i = 0; i < 7; ++i) {
        if ((numberToDisplay >> i) & 1) {
// set some pins as HIGH
pinDirections |= (1 << pinsettings.segmentPinOrder[i]);
pinState |= (1 << pinsettings.segmentPinOrder[i]);
//REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder[i]);
//REG_PORT_OUTSET0 |= (1 << pinsettings.segmentPinOrder[i]);
        }
    }
// put pins in HIGH state
REG_PORT_DIRSET0 = pinDirections;
REG_PORT_OUTSET0 = pinState;

    // PWM = 55 to turn the display ON (45 OFF)
    myPWM.setOnPercent(55);
    DelayMs(10000);

    // set all pins to inputs
    //REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);
    REG_PORT_DIRCLR0 = (PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);
//DelayMs(60000 * 15);
   
    /**/

    return true;
}

The first part seems to work (setting them as LOW) but they never go to HIGH state after that. Did I misunderstand something about how atomic registers work?
EDIT: if I do the same thing only for 1 of the pins for example:

REG_PORT_DIRSET0 = (1 << 5);
REG_PORT_OUTCLR0 = (1 << 5);

delay(10000);

REG_PORT_DIRCLR0 = (1 << 5);

delay(10000);

REG_PORT_DIRSET0 = (1 << 5);
REG_PORT_OUTSET0 =(1 << 5);

It looks like it works ok.
« Last Edit: March 09, 2022, 11:55:49 am by WILDERNESSBAGEL »
 

Offline WILDERNESSBAGELTopic starter

  • Contributor
  • Posts: 28
  • Country: hr
Re: ATSAMD10D13AS GPIO pin settings
« Reply #3 on: March 09, 2022, 02:27:25 pm »
I found a  guide https://community.atmel.com/sites/default/files/forum_attachments/PIN-IO-SAMD21-SAMR21_RevA_0.pdf#page=35 for GPIO and they set the LOW and high values using REG_PORT_OUT0  directly e.g. REG_PORT_OUT0 |= (1 << 5); I tried to modify my code to only use DIR0 and OUT0, however once again there is a problem after setting the pins to INPUT mode.

Code: [Select]

struct pinSettings{

    uint8_t number[10] = {0b01111101, 0b00000101, 0b01011011, 0b01001111, 0b00100111, 0b01101110, 0b01111110, 0b01000101, 0b01111111, 0b01101111};
    uint8_t segmentPinOrder[7] = {5, 6, 7, 8, 9, 14, 15};
    uint8_t clear = 0x00;
   
}pinsettings;

bool toggleNumber(uint8_t numberToDisplay){
    myPWM.begin();
    numberToDisplay = pinsettings.number[numberToDisplay];

uint32_t pinDirections = 0x00, pinState = 0x00;

for (uint8_t i = 0; i < 7; ++i) {
pinDirections |= (1 << pinsettings.segmentPinOrder[i]);
pinState |= (1 << pinsettings.segmentPinOrder[i]);
}

// set pins to OUTPUT and to LOW
REG_PORT_DIR0 |= pinDirections;
REG_PORT_OUT0 &= ~(pinState);

myPWM.setOnPercent(45);

DelayMs(10000);
pinDirections = 0x00;
pinState = 0x00;

        // set pins as INPUTS
REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);


    for (uint8_t i = 0; i < 7; ++i) {
        if ((numberToDisplay >> i) & 1) {
pinDirections |= (1 << pinsettings.segmentPinOrder[i]);
pinState |= (1 << pinsettings.segmentPinOrder[i]);
        }
    }
    // set pins to OUTPUs and HIGH
    REG_PORT_DIR0 |= pinDirections;
    REG_PORT_OUT0 |= pinState;

    myPWM.setOnPercent(55);
    DelayMs(10000);

    // set all pins to inputs
    REG_PORT_DIR0 &= ~(PORT_PA05 | PORT_PA06 | PORT_PA07 | PORT_PA08 | PORT_PA09 | PORT_PA14 | PORT_PA15);


    return true;
}

Since they used |= and &= in the tutorial for DIR0 I assume that should be OK. Any ideas on why they don't go in high state?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf