Change DDR/PORT order and add comment about intermediate state
This commit is contained in:
+45
-4
@@ -36,6 +36,47 @@
|
||||
#include <avr/io.h>
|
||||
#endif
|
||||
|
||||
/** AVR microcontrollers use two flip-flops per PIO stored in two
|
||||
separate registers: the data direction register (DDRx) and the
|
||||
port register (PORTx). The DDRx register controls the whether the
|
||||
pin is an input or an output; the PORTx register determines the
|
||||
output state when the pin is an output but also doubles as an
|
||||
enable for a pull-up resistor when the pin is an input.
|
||||
|
||||
Mode: DDRx PORTx
|
||||
Input, no pull-up 0 0
|
||||
Input, pull-up 0 1
|
||||
Output, low 1 0
|
||||
Output, high 1 1
|
||||
|
||||
These two registers cannot be changed at the same time so a
|
||||
transient intermediate state can occur if both these registers
|
||||
need to be changed. This is only a concern for pins that need to
|
||||
switched between being an input and an output; say for a
|
||||
bidirectional communication link.
|
||||
|
||||
Let's consider the scenario where we change DDRx before PORTx.
|
||||
|
||||
If we want to reconfigure a PIO from an input with no pull-up to a
|
||||
high output it will be momentarily a low output.
|
||||
|
||||
If we want to reconfigure a PIO from an input with pull-up to a
|
||||
low output it will be momentarily a high output.
|
||||
|
||||
Let's consider the alternative scenario where we change DDRx after PORTx.
|
||||
|
||||
If we want to reconfigure a PIO from an input with no pull-up to a
|
||||
high output it will be momentarily an input with a pull-up. This
|
||||
is not a bad option since a high-impedance load will not notice.
|
||||
|
||||
If we want to reconfigure a PIO from an input with pull-up to a
|
||||
low output it will be momentarily an input with no-pullup.
|
||||
|
||||
p.s. I am sure this subtle quirk has caused much grief to some
|
||||
embedded systems engineers.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/** Define port names; note not all the ports are available on some AVRs. */
|
||||
|
||||
@@ -58,7 +99,7 @@ typedef enum pio_config_enum
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* Define a PIO as a structure in terms of a port and a bit. */
|
||||
/* Define PIO as a unique integer. */
|
||||
#define PIO_DEFINE(PORT, PORTBIT) ((PORT) * 8 + (PORTBIT))
|
||||
|
||||
|
||||
@@ -164,13 +205,13 @@ bool pio_config_set (pio_t pio, pio_config_t config)
|
||||
switch (config)
|
||||
{
|
||||
case PIO_OUTPUT_LOW:
|
||||
PIO_DATA_ (pio) &= ~PIO_BITMASK_ (pio);
|
||||
PIO_DDR_ (pio) |= PIO_BITMASK_ (pio);
|
||||
PIO_DATA_ (pio) &= ~PIO_BITMASK_ (pio);
|
||||
return 1;
|
||||
|
||||
case PIO_OUTPUT_HIGH:
|
||||
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
|
||||
PIO_DDR_ (pio) |= PIO_BITMASK_ (pio);
|
||||
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
|
||||
return 1;
|
||||
|
||||
case PIO_INPUT:
|
||||
@@ -265,7 +306,7 @@ bool pio_output_get (pio_t pio)
|
||||
|
||||
/** Set pio to desired state.
|
||||
@param pio
|
||||
@param state value to write pio */
|
||||
@param state value to write to pio */
|
||||
static inline
|
||||
void pio_output_set (pio_t pio, bool state)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user