ATSAMD10D13AS GPIO pin settings - Page 1
Forum section: electronics / general

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: March 09, 2022, 08:35:29 am
content: 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 ATSAMD10D13AShttps://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:struct pinSettings{uint8_t number = {0b01111101, 0b00000101, 0b01011011, 0b01001111, 0b00100111, 0b01101110, 0b01111110, 0b01000101, 0b01111111, 0b01101111};uint8_t segmentPinOrder = {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 belowmyPWM.begin();numberToDisplay = pinsettings.number;for (uint8_t i = 0; i < 7; ++i) {// set all pins as outputs and set them to LOWREG_PORT_DIR0 |= (1 << pinsettings.segmentPinOrder);REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder);REG_PORT_OUTCLR0 |= (1 << pinsettings.segmentPinOrder);}myPWM.setOnPercent(45);DelayMs(10000);// st all pins as inputsREG_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 HIGHREG_PORT_DIR0 |= (1 << pinsettings.segmentPinOrder);REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder);REG_PORT_OUTSET0 |= (1 << pinsettings.segmentPinOrder);}}// PWM = 55 to turn the display ON (45 OFF)myPWM.setOnPercent(55);DelayMs(10000);// set all pins to inputsREG_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?

author: cv007
author_rank: Frequent Contributor
timestamp: March 09, 2022, 11:13:10 am
content: 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.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: March 09, 2022, 11:49:34 am
content: 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 folowingCode:bool toggleNumber(uint8_t numberToDisplay){myPWM.begin();numberToDisplay = pinsettings.number;uint32_t pinDirections = 0x00, pinState = 0x00;// set all pins to LOWfor (uint8_t i = 0; i < 7; ++i) {pinDirections |= (1 << pinsettings.segmentPinOrder);pinState |= (1 << pinsettings.segmentPinOrder);//REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder);//REG_PORT_OUTCLR0 |= (1 << pinsettings.segmentPinOrder);}// assign the registers to new valuesREG_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 stateREG_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 HIGHpinDirections |= (1 << pinsettings.segmentPinOrder);pinState |= (1 << pinsettings.segmentPinOrder);//REG_PORT_DIRSET0 |= (1 << pinsettings.segmentPinOrder);//REG_PORT_OUTSET0 |= (1 << pinsettings.segmentPinOrder);}}// put pins in HIGH stateREG_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.

author: WILDERNESSBAGEL
author_rank: Contributor
timestamp: March 09, 2022, 02:27:25 pm
content: I found a guidehttps://community.atmel.com/sites/default/files/forum_attachments/PIN-IO-SAMD21-SAMR21_RevA_0.pdf#page=35for 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:struct pinSettings{uint8_t number = {0b01111101, 0b00000101, 0b01011011, 0b01001111, 0b00100111, 0b01101110, 0b01111110, 0b01000101, 0b01111111, 0b01101111};uint8_t segmentPinOrder = {5, 6, 7, 8, 9, 14, 15};uint8_t clear = 0x00;}pinsettings;bool toggleNumber(uint8_t numberToDisplay){myPWM.begin();numberToDisplay = pinsettings.number;uint32_t pinDirections = 0x00, pinState = 0x00;for (uint8_t i = 0; i < 7; ++i) {pinDirections |= (1 << pinsettings.segmentPinOrder);pinState |= (1 << pinsettings.segmentPinOrder);}// set pins to OUTPUT and to LOWREG_PORT_DIR0 |= pinDirections;REG_PORT_OUT0 &= ~(pinState);myPWM.setOnPercent(45);DelayMs(10000);pinDirections = 0x00;pinState = 0x00;// set pins as INPUTSREG_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);pinState |= (1 << pinsettings.segmentPinOrder);}}// set pins to OUTPUs and HIGHREG_PORT_DIR0 |= pinDirections;REG_PORT_OUT0 |= pinState;myPWM.setOnPercent(55);DelayMs(10000);// set all pins to inputsREG_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?