Reading output pin level on SAMDG55

981 Views Asked by At

I'm building a firmware for a device based on Atmel/Microchip AT SAMG55.

In a simple function, trigger some relais connected to GPIO pins. Because I want to interlock different I/O, avoiding that 2 specific outputs are high level on the same time, I need to know the pin level I set before.

In another project, based on the SAMD21, there was a function that reads output pin state

static inline bool port_pin_get_output_level(const uint8_t gpio_pin)

The SAMG55 port library in ASF is quite different, so i tried ioport_get_pin_level(pin), but i'm not getting expected result. I think that it works only with pins configured as inputs.

Are there any recommended solutions?

3

There are 3 best solutions below

0
On BEST ANSWER

Referring to Figure 16-2 in the SAMG55 data sheet, and to sections 16.5.4 and 16.5.8:

16.5.4 Output Control

... The level driven on an I/O line can be determined by writing in the Set Output Data Register (PIO_SODR) and the Clear Output Data Register (PIO_CODR). These write operations, respectively, set and clear the Output Data Status Register (PIO_ODSR), which represents the data driven on the I/O lines. ...

16.5.8 Inputs

The level on each I/O line can be read through PIO_PDSR. This register indicates the level of the I/O lines regardless of their configuration, whether uniquely as an input, or driven by the PIO Controller, or driven by a peripheral. Reading the I/O line levels requires the clock of the PIO Controller to be enabled, otherwise PIO_PDSR reads the levels present on the I/O line at the time the clock was disabled.

So, as long as the pin is configured such that the actual level on the pin always corresponds to the level we're trying to drive - which is not the case with an open collector configuration, for example - then Tarick Welling's answer is correct: you can read the output state from the Output Data Status Register (PIO_ODSR).

However the true state of the pin, regardless of driver configuration, can be read (subject to a resynchronisation delay that may or may not be relevant in any given application) from the Pin Data Status Register (PIO_PDSR).

0
On

You can do some low level programming. You use the high level HAL functions to configure, set and reset the pins but before you do that you would. Read the value for the pin by addressing the data value of the register. In AVR that would be done by reading PORTx. In a STM32 this can be done by reading the value of GPIOx->ODR. You would of course then need to extract the correct pin but this can be done.

You can also look inside the definition of port_pin_get_output_level and check how they did it and convert that into the way this board/vendor/HAL does its addressing.

update:

When looking inside the datasheet for the SAM G55G/J. Page 340 gives us the answer we need.

The level driven on an I/O line can be determined by writing in the Set Output Data Register (PIO_SODR) and the Clear Output Data Register (PIO_CODR). These write operations, respectively, set and clear the Output Data Status Register (PIO_ODSR), which represents the data driven on the I/O lines.

So we can drive the output by writing to PIO_SODR and PIO_CODR to set and reset the pins respectively. But also read from PIO_ODSR this is a register which contains the state of the pin.

1
On

A quick google search turns up two options for Atmel/AVR controllers:

  1. read back from the same location you used to set your output value (PORTx register) This will give you the value that you have written into the register before.

  2. read the actual value using the PINx registers This will give you the value that you could actually measure on your device.

The difference between the two can be important: if you set a GPIO that is pulled down below the logic voltage threshold (i.e. if connected to GND) to HIGH, PORTx will read HIGH (the value you set) while PINx will read LOW (the actual value).

https://www.avrfreaks.net/forum/reading-pin-set-output