Use even faster and smaller PIO implemenation and add delay navswitch to fix read

main
Michael Hayes 14 years ago
parent d6cec3f386
commit 5e75e06e6a

@ -69,25 +69,25 @@ typedef enum pio_config_enum
/** Define a PIO as a unique 16 bit number encoding the low part of /** Define a PIO as a unique 16 bit number encoding the low part of
the PORT address in the low byte and the bit mask in the high the PORT address offset in the low byte and the bit mask in the
byte. PORTB is used for the pattern since PORTA is not always high byte. PORTB is used for the pattern since PORTA is not
defined for some AVRs. */ always defined for some AVRs. */
#define PIO_DEFINE(PORT, PORTBIT) (((((PORT) - PORT_B) * 3 + (uint16_t) (&PORTB)) & 0xff) + (BIT(PORTBIT) << 8)) #define PIO_DEFINE(PORT, PORTBIT) ((((PORT) - PORT_B) * 3) | (BIT(PORTBIT) << 8))
/** Private macro to lookup bitmask. */ /** Private macro to lookup bitmask. */
#define PIO_BITMASK_(pio) (pio >> 8) #define PIO_BITMASK_(PIO) ((PIO) >> 8)
/** Private macro to lookup port register. */ /** Private macro to lookup port register. */
#define PIO_PORT_(pio) ((pio_port_t)(pio & 0xff)) #define PIO_PORT_(PIO) (&PORTB + ((PIO) & 0xff))
/** Private macro to map a pio to its corresponding data direction /** Private macro to map a pio to its corresponding data direction
register (DDR). NB, the DDR and PORT registers must be separated register (DDR). NB, the DDR and PORT registers must be separated
by the same number of bytes in all cases. PORTB is used for the by the same number of bytes in all cases. PORTB is used for the
pattern since PORTA is not always defined for some AVRs. */ pattern since PORTA is not always defined for some AVRs. */
#define PIO_DDR_(pio) (*(PIO_PORT_ (pio) + (&DDRB - &PORTB))) #define PIO_DDR_(PIO) (*(PIO_PORT_ (PIO) + (&DDRB - &PORTB)))
/** Private macro to map a pio to its input register (PIN). NB, the /** Private macro to map a pio to its input register (PIN). NB, the
PIN and PORT registers must be separated by the same number of PIN and PORT registers must be separated by the same number of

@ -123,6 +123,13 @@ navswitch_update (void)
/* Switch PIO to an input to read switch. */ /* Switch PIO to an input to read switch. */
pio_config_set (navswitch_cfg[i].pio, PIO_PULLUP); pio_config_set (navswitch_cfg[i].pio, PIO_PULLUP);
/* I'm unsure why this is needed. It wasn't required for the
slightly slower PIO implementation. There may be a minimum
number of CPU clock cycles for the synchronising flip flops
to propagate the input state? */
DELAY_US (1.0);
navswitch_state[i].current = pio_input_get (navswitch_cfg[i].pio) == 0; navswitch_state[i].current = pio_input_get (navswitch_cfg[i].pio) == 0;
/* Restore PIO state. */ /* Restore PIO state. */
@ -136,5 +143,3 @@ void navswitch_init (void)
{ {
/* Nothing to do since we configure PIOs when polling the switch. */ /* Nothing to do since we configure PIOs when polling the switch. */
} }

@ -2,6 +2,122 @@
@author M. P. Hayes, UCECE @author M. P. Hayes, UCECE
@date 11 Jan 2006 @date 11 Jan 2006
@brief PIO hardware abstraction for AVR microcontroller. @brief PIO hardware abstraction for AVR microcontroller.
@note This implementation is empty; inline functions are used @note Inline functions are used in pio.h instead for performance.
in pio.h instead for performance.
*/ */
#include "system.h"
#include "pio.h"
#ifdef DEBUG
/** Configure pio.
@param pio PIO to configure
@param config PIO configuration type
@return non-zero for success. */
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);
return 1;
case PIO_OUTPUT_HIGH:
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
PIO_DDR_ (pio) |= PIO_BITMASK_ (pio);
return 1;
case PIO_INPUT:
PIO_DDR_ (pio) &= ~PIO_BITMASK_ (pio);
PIO_DATA_ (pio) &= ~PIO_BITMASK_ (pio);
return 1;
case PIO_PULLUP:
PIO_DDR_ (pio) &= ~PIO_BITMASK_ (pio);
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
return 1;
default:
return 0;
}
}
/** Return pio configuration
@param pio
@return config */
pio_config_t pio_config_get (pio_t pio)
{
bool ddr;
bool port;
ddr = PIO_DDR_ (pio) & PIO_BITMASK_ (pio);
port = PIO_DATA_ (pio) & PIO_BITMASK_ (pio);
if (ddr)
{
if (port)
return PIO_OUTPUT_HIGH;
else
return PIO_OUTPUT_LOW;
}
if (port)
return PIO_PULLUP;
return PIO_INPUT;
}
/** Set pio high.
@param pio */
void pio_output_high (pio_t pio)
{
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
}
/** Set pio low.
@param pio */
void pio_output_low (pio_t pio)
{
PIO_DATA_ (pio) &= ~PIO_BITMASK_ (pio);
}
/** Toggle pio.
@param pio */
void pio_output_toggle (pio_t pio)
{
PIO_DATA_ (pio) ^= PIO_BITMASK_ (pio);
}
/** Read input state from pio.
@param pio
@return input state of pio */
bool pio_input_get (pio_t pio)
{
return (PIO_PIN_ (pio) & PIO_BITMASK_ (pio)) != 0;
}
/** Get output state of pio.
@param pio
@return output state of pio */
bool pio_output_get (pio_t pio)
{
return (PIO_DATA_ (pio) & PIO_BITMASK_ (pio)) != 0;
}
/** Set pio to desired state.
@param pio
@param state value to write pio */
void pio_output_set (pio_t pio, bool state)
{
state ? pio_output_high (pio) : pio_output_low (pio);
}
#endif

@ -39,44 +39,11 @@
/** Define port names, note not all the ports are available on some AVRs. */ /** Define port names, note not all the ports are available on some AVRs. */
#ifdef PORTA enum {PORT_A, PORT_B, PORT_C, PORT_D, PORT_E, PORT_F, PORT_G};
#define PORT_A &PORTA
#endif
#ifdef PORTB
#define PORT_B &PORTB
#endif
#ifdef PORTC
#define PORT_C &PORTC
#endif
#ifdef PORTD
#define PORT_D &PORTD
#endif
#ifdef PORTE
#define PORT_E &PORTE
#endif
#ifdef PORTF
#define PORT_F &PORTF
#endif
#ifdef PORTG
#define PORT_G &PORTG
#endif
typedef volatile uint8_t *pio_port_t; typedef volatile uint8_t *pio_port_t;
typedef uint8_t pio_mask_t; typedef uint8_t pio_mask_t;
typedef uint16_t pio_t;
typedef struct
{
pio_port_t port;
pio_mask_t bitmask;
} pio_t;
/** Define PIO pin types. The two flavours of PIO_OUTPUT are to /** Define PIO pin types. The two flavours of PIO_OUTPUT are to
@ -99,24 +66,26 @@ typedef enum pio_config_enum
*/ */
/** Define a PIO as a compound literal structure in terms of a port and /** Define a PIO as a unique 16 bit number encoding the low part of
a bitmask. */ the PORT address in the low byte and the bit mask in the high
#define PIO_DEFINE(PORT, PORTBIT) (pio_t){.port = PORT, .bitmask = BIT (PORTBIT)} byte. PORTB is used for the pattern since PORTA is not always
defined for some AVRs. */
#define PIO_DEFINE(PORT, PORTBIT) ((((PORT) - PORT_B) * 3) | (BIT(PORTBIT) << 8))
/** Private macro to lookup bitmask. */ /** Private macro to lookup bitmask. */
#define PIO_BITMASK_(pio) (pio.bitmask) #define PIO_BITMASK_(PIO) ((PIO) >> 8)
/** Private macro to lookup port register. */ /** Private macro to lookup port register. */
#define PIO_PORT_(pio) (pio.port) #define PIO_PORT_(PIO) (&PORTB + ((PIO) & 0xff))
/** Private macro to map a pio to its corresponding data direction /** Private macro to map a pio to its corresponding data direction
register (DDR). NB, the DDR and PORT registers must be separated register (DDR). NB, the DDR and PORT registers must be separated
by the same number of bytes in all cases. PORTB is used for the by the same number of bytes in all cases. PORTB is used for the
pattern since PORTA is not always defined for some AVRs. */ pattern since PORTA is not always defined for some AVRs. */
#define PIO_DDR_(pio) (*(PIO_PORT_ (pio) + (&DDRB - &PORTB))) #define PIO_DDR_(PIO) (*(PIO_PORT_ (PIO) + (&DDRB - &PORTB)))
/** Private macro to map a pio to its input register (PIN). NB, the /** Private macro to map a pio to its input register (PIN). NB, the
PIN and PORT registers must be separated by the same number of PIN and PORT registers must be separated by the same number of
@ -128,6 +97,59 @@ typedef enum pio_config_enum
#define PIO_DATA_(pio) (*PIO_PORT_ (pio)) #define PIO_DATA_(pio) (*PIO_PORT_ (pio))
#ifdef DEBUG
/** Configure pio.
@param pio PIO to configure
@param config PIO configuration type
@return non-zero for success. */
bool pio_config_set (pio_t pio, pio_config_t config);
/** Return pio configuration
@param pio
@return config */
pio_config_t pio_config_get (pio_t pio);
/** Set pio high.
@param pio */
void pio_output_high (pio_t pio);
/** Set pio low.
@param pio */
void pio_output_low (pio_t pio);
/** Toggle pio.
@param pio */
void pio_output_toggle (pio_t pio);
/** Read input state from pio.
@param pio
@return input state of pio */
bool pio_input_get (pio_t pio);
/** Read input state from pio.
@param pio
@return input state of pio */
bool pio_input_get (pio_t pio);
/** Get output state of pio.
@param pio
@return output state of pio */
bool pio_output_get (pio_t pio);
/** Set pio to desired state.
@param pio
@param state value to write pio */
void pio_output_set (pio_t pio, bool state);
#else
/** Configure pio. /** Configure pio.
@param pio PIO to configure @param pio PIO to configure
@ -248,7 +270,6 @@ void pio_output_set (pio_t pio, bool state)
state ? pio_output_high (pio) : pio_output_low (pio); state ? pio_output_high (pio) : pio_output_low (pio);
} }
/** Set input state for pio (this is only for use by the test scaffold). /** Set input state for pio (this is only for use by the test scaffold).
@param pio @param pio
@param state value for pio input */ @param state value for pio input */
@ -260,6 +281,6 @@ void pio_input_set (pio_t pio, bool state)
else else
PIO_PIN_ (pio) &= ~PIO_BITMASK_ (pio); PIO_PIN_ (pio) &= ~PIO_BITMASK_ (pio);
} }
#endif
#endif #endif

Loading…
Cancel
Save