Generate callgraph
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
#ifndef AVRTEST_H
|
||||
#define AVRTEST_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
typedef struct SFR
|
||||
{
|
||||
uint8_t PORTB;
|
||||
uint8_t DDRB;
|
||||
uint8_t PINB;
|
||||
uint8_t PORTC;
|
||||
uint8_t DDRC;
|
||||
uint8_t PINC;
|
||||
uint8_t PORTD;
|
||||
uint8_t DDRD;
|
||||
uint8_t PIND;
|
||||
} SFR_t;
|
||||
|
||||
|
||||
#define PORTB SFR.PORTB
|
||||
#define PORTC SFR.PORTC
|
||||
#define PORTD SFR.PORTD
|
||||
#define DDRB SFR.DDRB
|
||||
#define DDRC SFR.DDRC
|
||||
#define DDRD SFR.DDRD
|
||||
#define PINB SFR.PINB
|
||||
#define PINC SFR.PINC
|
||||
#define PIND SFR.PINC
|
||||
|
||||
extern SFR_t SFR;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
#define DELAY_US(US)
|
||||
@@ -0,0 +1,85 @@
|
||||
/** @file eeprom.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 15 May 2007
|
||||
@brief
|
||||
*/
|
||||
#include "system.h"
|
||||
#include "eeprom.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define EEPROM_SIZE 512
|
||||
#define EEPROM_FILENAME "ucfk_eeprom.dat"
|
||||
|
||||
|
||||
static void
|
||||
eeprom_file_write (void *buffer, eeprom_size_t size)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (EEPROM_FILENAME, "w");
|
||||
if (fp)
|
||||
{
|
||||
fwrite (buffer, size, 1, fp);
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
eeprom_file_read (void *buffer, eeprom_size_t size)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen (EEPROM_FILENAME, "r");
|
||||
if (!fp)
|
||||
{
|
||||
/* If file not present assume EEPROM is erased and thus
|
||||
contains the values 0xff. */
|
||||
memset (buffer, 0xff, size);
|
||||
eeprom_file_write (buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
fread (buffer, size, 1, fp);
|
||||
fclose (fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read SIZE bytes from ADDR into BUFFER. */
|
||||
eeprom_size_t
|
||||
eeprom_read (eeprom_addr_t addr, void *buffer, eeprom_size_t size)
|
||||
{
|
||||
eeprom_size_t i;
|
||||
uint8_t *data = buffer;
|
||||
uint8_t eeprom[EEPROM_SIZE];
|
||||
|
||||
eeprom_file_read (eeprom, EEPROM_SIZE);
|
||||
|
||||
for (i = 0; i < size && addr < EEPROM_SIZE; i++)
|
||||
data[i] = eeprom[addr++];
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Write SIZE bytes to ADDR from BUFFER. */
|
||||
eeprom_size_t
|
||||
eeprom_write (eeprom_addr_t addr, const void *buffer, eeprom_size_t size)
|
||||
{
|
||||
eeprom_size_t i;
|
||||
const uint8_t *data = buffer;
|
||||
uint8_t eeprom[EEPROM_SIZE];
|
||||
|
||||
eeprom_file_read (eeprom, EEPROM_SIZE);
|
||||
|
||||
for (i = 0; i < size && addr < EEPROM_SIZE; i++)
|
||||
eeprom[addr++] = data[i];
|
||||
|
||||
eeprom_file_write (eeprom, EEPROM_SIZE);
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/** @file eeprom.h
|
||||
@author Michael Hayes
|
||||
@date 13 Nov 2006
|
||||
@brief Routines to read/write internal EEPROM.
|
||||
|
||||
@defgroup eeprom EEPROM driver
|
||||
|
||||
This module implements a driver to read/write the EEPROM of an
|
||||
ATmega microcontroller. The EEPROM is useful for storing
|
||||
persistent data when the power is removed.
|
||||
*/
|
||||
|
||||
#ifndef EEPROM_H
|
||||
#define EEPROM_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
typedef uint16_t eeprom_addr_t;
|
||||
typedef uint16_t eeprom_size_t;
|
||||
|
||||
/* Read SIZE bytes from ADDR into BUFFER. */
|
||||
extern eeprom_size_t
|
||||
eeprom_read (eeprom_addr_t addr, void *buffer, eeprom_size_t size);
|
||||
|
||||
|
||||
/* Write SIZE bytes to ADDR from BUFFER. */
|
||||
extern eeprom_size_t
|
||||
eeprom_write (eeprom_addr_t addr, const void *buffer, eeprom_size_t size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/** @file ir_uart.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 1 Aug 2011
|
||||
@brief This is just a stub that does nothing.
|
||||
*/
|
||||
#include "system.h"
|
||||
#include "ir_uart.h"
|
||||
|
||||
|
||||
/* Return non-zero if there is a character ready to be read. */
|
||||
bool
|
||||
ir_uart_read_ready_p (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read character from IR_UART. This blocks if nothing
|
||||
is available to read. */
|
||||
int8_t
|
||||
ir_uart_getc (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return non-zero if a character can be written without blocking. */
|
||||
bool
|
||||
ir_uart_write_ready_p (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return non-zero if transmitter finished. */
|
||||
bool
|
||||
ir_uart_write_finished_p (void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Write character to IR_UART. This returns zero if
|
||||
the character could not be written. */
|
||||
int8_t
|
||||
ir_uart_putc (__unused__ char ch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Write string to IR_UART. */
|
||||
void
|
||||
ir_uart_puts (__unused__ const char *str)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* Initialise ir_uart and set baud rate. */
|
||||
uint8_t
|
||||
ir_uart_init (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/** @file ir_uart.h
|
||||
@author Michael Hayes
|
||||
@date 10 December 2004
|
||||
*/
|
||||
|
||||
#ifndef IR_UART_H
|
||||
#define IR_UART_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#ifndef IR_UART_BAUD_RATE
|
||||
#define IR_UART_BAUD_RATE 2400
|
||||
#endif
|
||||
|
||||
|
||||
/* Return non-zero if there is a character ready to be read. */
|
||||
bool
|
||||
ir_uart_read_ready_p (void);
|
||||
|
||||
|
||||
/* Read character from IR_UART. This blocks if nothing
|
||||
is available to read. */
|
||||
int8_t
|
||||
ir_uart_getc (void);
|
||||
|
||||
|
||||
/* Return non-zero if a character can be written without blocking. */
|
||||
bool
|
||||
ir_uart_write_ready_p (void);
|
||||
|
||||
|
||||
/* Return non-zero if transmitter finished. */
|
||||
bool
|
||||
ir_uart_write_finished_p (void);
|
||||
|
||||
|
||||
/* Write character to IR_UART. This returns zero if
|
||||
the character could not be written. */
|
||||
int8_t
|
||||
ir_uart_putc (char ch);
|
||||
|
||||
|
||||
/* Write string to IR_UART. */
|
||||
void
|
||||
ir_uart_puts (const char *str);
|
||||
|
||||
|
||||
/* Initialise ir_uart and set baud rate. */
|
||||
uint8_t
|
||||
ir_uart_init (void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/** @file mgetkey.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 17 July 2011
|
||||
@brief Non-blocking raw keyboard reading.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mgetkey.h"
|
||||
|
||||
static struct termios tty_attr_save;
|
||||
static int tty_init = 0;
|
||||
|
||||
|
||||
/* Get the terminal attributes. */
|
||||
static int mgetkey_attr_get (struct termios *ptty_attr)
|
||||
{
|
||||
if (tcgetattr (STDIN_FILENO, ptty_attr) == -1)
|
||||
{
|
||||
perror ("mgetkey: Cannot get tty attributes");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Set terminal attributes ensuring that the original attributes are
|
||||
saved. */
|
||||
static int mgetkey_attr_set (struct termios *ptty_attr)
|
||||
{
|
||||
if (tcsetattr (STDIN_FILENO, TCSANOW, ptty_attr) == -1)
|
||||
{
|
||||
perror ("mgetkey: Cannot set tty attributes");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int mgetkey_init (void)
|
||||
{
|
||||
struct termios tty_attr;
|
||||
|
||||
if (!tty_init)
|
||||
{
|
||||
if (!mgetkey_attr_get (&tty_attr_save))
|
||||
return 0;
|
||||
|
||||
/* Restore terminal attributes on exit. */
|
||||
atexit (mgetkey_reset);
|
||||
tty_init = 1;
|
||||
}
|
||||
|
||||
/* Get terminal attributes. */
|
||||
if (!mgetkey_attr_get (&tty_attr))
|
||||
return 0;
|
||||
|
||||
tty_attr.c_lflag &= ~ECHO; /* No echo. */
|
||||
tty_attr.c_lflag &= ~ICANON; /* No canonical processing. */
|
||||
tty_attr.c_cc[VMIN] = 0; /* Don't block. */
|
||||
tty_attr.c_cc[VTIME] = 0; /* Don't block. */
|
||||
|
||||
/* Set terminal attributes. */
|
||||
return mgetkey_attr_set (&tty_attr);
|
||||
}
|
||||
|
||||
|
||||
/* Restore the terminal attributes. */
|
||||
void mgetkey_reset (void)
|
||||
{
|
||||
mgetkey_attr_set (&tty_attr_save);
|
||||
}
|
||||
|
||||
|
||||
/* Read a single key stroke from the keyboard. This blocks until
|
||||
a key is typed. Note that the key is not echoed. */
|
||||
int mgetkey (void)
|
||||
{
|
||||
int key;
|
||||
|
||||
if (!tty_init)
|
||||
mgetkey_init ();
|
||||
|
||||
key = getchar ();
|
||||
if (key == -1)
|
||||
key = 0;
|
||||
return key;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/** @file mgetkey.h
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 17 July 2011
|
||||
@brief Non-blocking raw keyboard reading.
|
||||
*/
|
||||
|
||||
#ifndef MGETKEY_H
|
||||
#define MGETKEY_H
|
||||
|
||||
/* Read a single key stroke from the keyboard. If no key has been
|
||||
pressed then zero is returned. Note that the key is not
|
||||
echoed. */
|
||||
int mgetkey (void);
|
||||
|
||||
|
||||
/* Restore terminal settings. */
|
||||
void mgetkey_reset (void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
/** @file pio.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 11 Jan 2006
|
||||
@brief PIO hardware abstraction for AVR microcontroller.
|
||||
@note This implementation is empty; inline functions are used
|
||||
in pio.h instead for performance.
|
||||
*/
|
||||
@@ -0,0 +1,265 @@
|
||||
/** @file pio.h
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 11 Jan 2006
|
||||
@brief PIO hardware abstraction for AVR microcontroller.
|
||||
@note Macros and inline functions are used to avoid function
|
||||
call overhead and to allow compile-time constant folding.
|
||||
|
||||
@defgroup pio PIO driver
|
||||
|
||||
This module implements a driver for general purpose I/O ports.
|
||||
Its purpose is to provide a microcontroller independent
|
||||
abstraction of a PIO pin. Here's an example:
|
||||
|
||||
@code
|
||||
#include "pio.h"
|
||||
|
||||
#define LED_PIO PIO_DEFINE (PORT_B, 5)
|
||||
|
||||
void main (void)
|
||||
{
|
||||
system_init ();
|
||||
pio_config_set (LED_PIO, PIO_OUTPUT_LOW);
|
||||
|
||||
pio_output_high (LED_PIO);
|
||||
|
||||
while (1);
|
||||
}
|
||||
@endcode
|
||||
|
||||
In this example, when port B5 is configured as an output it is set
|
||||
low.
|
||||
*/
|
||||
#ifndef PIO_H
|
||||
#define PIO_H
|
||||
|
||||
#include "system.h"
|
||||
#include "avrtest.h"
|
||||
|
||||
|
||||
/** Define port names, note not all the ports are available on some AVRs. */
|
||||
|
||||
#ifdef PORTA
|
||||
#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 uint8_t pio_mask_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
|
||||
ensure the port is configured without glitching due to the time
|
||||
taken before calling pio_output_set. */
|
||||
typedef enum pio_config_enum
|
||||
{
|
||||
PIO_INPUT = 1, /** Configure as input pin. */
|
||||
PIO_PULLUP, /** Configure as input pin with pullup. */
|
||||
PIO_OUTPUT_LOW, /** Configure as output, initially low. */
|
||||
PIO_OUTPUT_HIGH, /** Configure as output, initially high. */
|
||||
} pio_config_t;
|
||||
|
||||
|
||||
/** DDR PORT Comment
|
||||
0 0 High impedance input
|
||||
0 1 Weak pullup input
|
||||
1 0 Output low
|
||||
1 1 Output high
|
||||
*/
|
||||
|
||||
|
||||
/** Define a PIO as a compound literal structure in terms of a port and
|
||||
a bitmask. */
|
||||
#define PIO_DEFINE(PORT, PORTBIT) (pio_t){.port = PORT, .bitmask = BIT (PORTBIT)}
|
||||
|
||||
|
||||
/** Private macro to lookup bitmask. */
|
||||
#define PIO_BITMASK_(pio) (pio.bitmask)
|
||||
|
||||
|
||||
/** Private macro to lookup port register. */
|
||||
#define PIO_PORT_(pio) (pio.port)
|
||||
|
||||
|
||||
/** Private macro to map a pio to its corresponding data direction
|
||||
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
|
||||
pattern since PORTA is not always defined for some AVRs. */
|
||||
#define PIO_DDR_(pio) (*(PIO_PORT_ (pio) + (&DDRB - &PORTB)))
|
||||
|
||||
/** 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
|
||||
bytes in all cases. PORTB is used for the pattern since PORTA is
|
||||
not always defined for some AVRs. */
|
||||
#define PIO_PIN_(pio) (*(PIO_PORT_ (pio) + (&PINB - &PORTB)))
|
||||
|
||||
/** Private macro to access a pio data register. */
|
||||
#define PIO_DATA_(pio) (*PIO_PORT_ (pio))
|
||||
|
||||
|
||||
|
||||
/** Configure pio.
|
||||
@param pio PIO to configure
|
||||
@param config PIO configuration type
|
||||
@return non-zero for success. */
|
||||
static inline
|
||||
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 */
|
||||
static inline
|
||||
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 */
|
||||
static inline
|
||||
void pio_output_high (pio_t pio)
|
||||
{
|
||||
PIO_DATA_ (pio) |= PIO_BITMASK_ (pio);
|
||||
}
|
||||
|
||||
|
||||
/** Set pio low.
|
||||
@param pio */
|
||||
static inline
|
||||
void pio_output_low (pio_t pio)
|
||||
{
|
||||
PIO_DATA_ (pio) &= ~PIO_BITMASK_ (pio);
|
||||
}
|
||||
|
||||
|
||||
/** Toggle pio.
|
||||
@param pio */
|
||||
static inline
|
||||
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 */
|
||||
static inline
|
||||
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 */
|
||||
static inline
|
||||
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 */
|
||||
static inline
|
||||
void pio_output_set (pio_t pio, bool state)
|
||||
{
|
||||
state ? pio_output_high (pio) : pio_output_low (pio);
|
||||
}
|
||||
|
||||
|
||||
/** Set input state for pio (this is only for use by the test scaffold).
|
||||
@param pio
|
||||
@param state value for pio input */
|
||||
static inline
|
||||
void pio_input_set (pio_t pio, bool state)
|
||||
{
|
||||
if (state)
|
||||
PIO_PIN_ (pio) |= PIO_BITMASK_ (pio);
|
||||
else
|
||||
PIO_PIN_ (pio) &= ~PIO_BITMASK_ (pio);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,402 @@
|
||||
/** @file system.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 15 May 2007
|
||||
@brief Test scaffold for UCFK4.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "avrtest.h"
|
||||
#include "pio.h"
|
||||
#include "mgetkey.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/** This needs to be at least 50 * 5 for a refresh rate of 50 Hz. */
|
||||
#define SYSTEM_UPDATE_RATE 400
|
||||
|
||||
#define SYSTEM_KEYBOARD_RELEASE_PERIOD 0.2
|
||||
|
||||
#define SYSTEM_DISPLAY_PERSISTENCE_PERIOD 0.01
|
||||
|
||||
|
||||
SFR_t SFR = {0, 0, ~0, 0, 0, ~0, 0, 0, ~0};
|
||||
|
||||
|
||||
/* Define PIO pins driving LED matrix rows and columns. */
|
||||
static const pio_t ledmat_rows[] =
|
||||
{
|
||||
LEDMAT_ROW1_PIO,
|
||||
LEDMAT_ROW2_PIO,
|
||||
LEDMAT_ROW3_PIO,
|
||||
LEDMAT_ROW4_PIO,
|
||||
LEDMAT_ROW5_PIO,
|
||||
LEDMAT_ROW6_PIO,
|
||||
LEDMAT_ROW7_PIO
|
||||
};
|
||||
|
||||
static const pio_t ledmat_cols[] =
|
||||
{
|
||||
LEDMAT_COL1_PIO,
|
||||
LEDMAT_COL2_PIO,
|
||||
LEDMAT_COL3_PIO,
|
||||
LEDMAT_COL4_PIO,
|
||||
LEDMAT_COL5_PIO
|
||||
};
|
||||
|
||||
|
||||
typedef enum {NAVSWITCH_NONE, NAVSWITCH_EAST, NAVSWITCH_SOUTH,
|
||||
NAVSWITCH_WEST, NAVSWITCH_NORTH, NAVSWITCH_PUSH} system_navswitch_t;
|
||||
|
||||
typedef enum {BUTTON_NONE, BUTTON_1} system_button_t;
|
||||
|
||||
|
||||
static void system_display_update (void)
|
||||
{
|
||||
int row;
|
||||
int col;
|
||||
/* Persistence time (s). */
|
||||
double tau = SYSTEM_DISPLAY_PERSISTENCE_PERIOD;
|
||||
/* Sample period (s). */
|
||||
double delta_t;
|
||||
/* Exponential filter parameter. */
|
||||
double alpha;
|
||||
static uint8_t tdisplay[LEDMAT_ROWS_NUM][LEDMAT_COLS_NUM];
|
||||
|
||||
delta_t = 1.0 / SYSTEM_UPDATE_RATE;
|
||||
alpha = tau / (tau + delta_t);
|
||||
|
||||
for (row = 0; row < LEDMAT_ROWS_NUM; row++)
|
||||
{
|
||||
for (col = 0; col < LEDMAT_COLS_NUM; col++)
|
||||
{
|
||||
uint8_t on;
|
||||
|
||||
/* Determine if pixel is on. */
|
||||
on = !pio_output_get (ledmat_rows[row])
|
||||
&& !pio_output_get (ledmat_cols[col]);
|
||||
|
||||
/* Apply exponential filter to provide some persistence.
|
||||
This has an impulse response of exp(-t / tau) u(t). */
|
||||
tdisplay[row][col] = tdisplay[row][col] * alpha + (1 - alpha) * 100 * on;
|
||||
|
||||
printf ("%c", tdisplay[row][col] > 1 ? '@' : '.');
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
printf ("\n");
|
||||
/* Move cursor up. */
|
||||
printf ("\e[%dA", LEDMAT_ROWS_NUM + 1);
|
||||
}
|
||||
|
||||
|
||||
static void system_navswitch_set (system_navswitch_t navswitch, bool state)
|
||||
{
|
||||
switch (navswitch)
|
||||
{
|
||||
case NAVSWITCH_NONE:
|
||||
break;
|
||||
|
||||
case NAVSWITCH_NORTH:
|
||||
pio_input_set (NAVSWITCH_NORTH_PIO, !state);
|
||||
break;
|
||||
|
||||
case NAVSWITCH_EAST:
|
||||
pio_input_set (NAVSWITCH_EAST_PIO, !state);
|
||||
break;
|
||||
|
||||
case NAVSWITCH_SOUTH:
|
||||
pio_input_set (NAVSWITCH_SOUTH_PIO, !state);
|
||||
break;
|
||||
|
||||
case NAVSWITCH_WEST:
|
||||
pio_input_set (NAVSWITCH_WEST_PIO, !state);
|
||||
break;
|
||||
|
||||
case NAVSWITCH_PUSH:
|
||||
pio_input_set (NAVSWITCH_PUSH_PIO, !state);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void system_navswitch_press (system_navswitch_t navswitch)
|
||||
{
|
||||
system_navswitch_set (navswitch, 1);
|
||||
}
|
||||
|
||||
|
||||
static void system_navswitch_release (system_navswitch_t navswitch)
|
||||
{
|
||||
system_navswitch_set (navswitch, 0);
|
||||
}
|
||||
|
||||
|
||||
static void system_navswitch_select (system_navswitch_t navswitch)
|
||||
{
|
||||
static system_navswitch_t last = NAVSWITCH_NONE;
|
||||
static int counter;
|
||||
|
||||
if (navswitch == NAVSWITCH_NONE)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
counter--;
|
||||
if (!counter)
|
||||
{
|
||||
system_navswitch_release (last);
|
||||
last = NAVSWITCH_NONE;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
counter = SYSTEM_UPDATE_RATE * SYSTEM_KEYBOARD_RELEASE_PERIOD;
|
||||
|
||||
if (last == navswitch)
|
||||
return;
|
||||
|
||||
system_navswitch_release (last);
|
||||
|
||||
last = navswitch;
|
||||
|
||||
system_navswitch_press (navswitch);
|
||||
}
|
||||
|
||||
|
||||
static void system_button_set (system_button_t button, bool state)
|
||||
{
|
||||
switch (button)
|
||||
{
|
||||
case BUTTON_NONE:
|
||||
break;
|
||||
|
||||
case BUTTON_1:
|
||||
/* Active high. */
|
||||
pio_input_set (BUTTON1_PIO, state);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void system_button_press (system_button_t button)
|
||||
{
|
||||
system_button_set (button, 1);
|
||||
}
|
||||
|
||||
|
||||
static void system_button_release (system_button_t button)
|
||||
{
|
||||
system_button_set (button, 0);
|
||||
}
|
||||
|
||||
|
||||
static void system_button_select (system_button_t button)
|
||||
{
|
||||
static system_button_t last = BUTTON_NONE;
|
||||
static int counter;
|
||||
|
||||
if (button == BUTTON_NONE)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
counter--;
|
||||
if (!counter)
|
||||
{
|
||||
system_button_release (last);
|
||||
last = BUTTON_NONE;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
counter = SYSTEM_UPDATE_RATE * SYSTEM_KEYBOARD_RELEASE_PERIOD;
|
||||
|
||||
if (last == button)
|
||||
return;
|
||||
|
||||
system_button_release (last);
|
||||
|
||||
last = button;
|
||||
|
||||
system_button_press (button);
|
||||
}
|
||||
|
||||
|
||||
static void system_keyboard_init (void)
|
||||
{
|
||||
system_navswitch_release (NAVSWITCH_PUSH);
|
||||
system_navswitch_release (NAVSWITCH_NORTH);
|
||||
system_navswitch_release (NAVSWITCH_EAST);
|
||||
system_navswitch_release (NAVSWITCH_SOUTH);
|
||||
system_navswitch_release (NAVSWITCH_WEST);
|
||||
|
||||
system_button_release (BUTTON_1);
|
||||
}
|
||||
|
||||
|
||||
static void system_keyboard_update (void)
|
||||
{
|
||||
static int state = 0;
|
||||
int key;
|
||||
|
||||
system_navswitch_select (NAVSWITCH_NONE);
|
||||
system_button_select (BUTTON_NONE);
|
||||
|
||||
key = mgetkey ();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
switch (key)
|
||||
{
|
||||
case '\e':
|
||||
/* Have escape character. */
|
||||
state = 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
system_navswitch_select (NAVSWITCH_PUSH);
|
||||
break;
|
||||
|
||||
case '.':
|
||||
system_button_select (BUTTON_1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (key == '[')
|
||||
state = 2;
|
||||
else
|
||||
state = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
state = 0;
|
||||
switch (key)
|
||||
{
|
||||
case 'A':
|
||||
system_navswitch_select (NAVSWITCH_NORTH);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
system_navswitch_select (NAVSWITCH_SOUTH);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
system_navswitch_select (NAVSWITCH_EAST);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
system_navswitch_select (NAVSWITCH_WEST);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void system_update (void)
|
||||
{
|
||||
system_display_update ();
|
||||
system_keyboard_update ();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
system_handler (__unused__ int sig, __unused__ siginfo_t *si,
|
||||
__unused__ void *uc)
|
||||
{
|
||||
system_update ();
|
||||
}
|
||||
|
||||
|
||||
typedef void (*sighandler_t)(int, siginfo_t *, void *);
|
||||
|
||||
static int system_interrupt_init (sighandler_t handler, int rate)
|
||||
{
|
||||
timer_t timerid;
|
||||
struct sigevent sev;
|
||||
struct itimerspec its;
|
||||
long long period_ns;
|
||||
sigset_t mask;
|
||||
struct sigaction sa;
|
||||
static int signum = 0;
|
||||
|
||||
/* When debugging with gdb use "handle SIG34 noprint". */
|
||||
|
||||
if (!signum)
|
||||
signum = SIGRTMIN;
|
||||
|
||||
/* Establish handler for timer signal. */
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handler;
|
||||
sigemptyset (&sa.sa_mask);
|
||||
if (sigaction (signum, &sa, NULL) == -1)
|
||||
{
|
||||
perror ("sigaction");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Block timer signal temporarily. */
|
||||
sigemptyset (&mask);
|
||||
sigaddset (&mask, signum);
|
||||
if (sigprocmask (SIG_SETMASK, &mask, NULL) == -1)
|
||||
{
|
||||
perror ("sigprocmask");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Create the timer. */
|
||||
sev.sigev_notify = SIGEV_SIGNAL;
|
||||
sev.sigev_signo = signum;
|
||||
sev.sigev_value.sival_ptr = &timerid;
|
||||
if (timer_create (CLOCK_REALTIME, &sev, &timerid) == -1)
|
||||
{
|
||||
perror ("timer_create");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Start the timer */
|
||||
period_ns = 1000000000 / rate;
|
||||
its.it_value.tv_sec = period_ns / 1000000000;
|
||||
its.it_value.tv_nsec = period_ns % 1000000000;
|
||||
its.it_interval.tv_sec = its.it_value.tv_sec;
|
||||
its.it_interval.tv_nsec = its.it_value.tv_nsec;
|
||||
if (timer_settime (timerid, 0, &its, NULL) == -1)
|
||||
{
|
||||
perror ("timer_settime");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Unlock the timer signal, so that timer notification
|
||||
can be delivered. */
|
||||
if (sigprocmask (SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
{
|
||||
perror ("sigprocmask");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
signum++;
|
||||
return signum;
|
||||
}
|
||||
|
||||
|
||||
void system_init (void)
|
||||
{
|
||||
system_keyboard_init ();
|
||||
|
||||
system_interrupt_init (system_handler, SYSTEM_UPDATE_RATE);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/** @file system.h
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 15 May 2007
|
||||
@brief System specific definitions
|
||||
*/
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
/* Data typedefs. */
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t bool;
|
||||
|
||||
|
||||
/* Useful macros. */
|
||||
#define BIT(X) (1 << (X))
|
||||
|
||||
#define ARRAY_SIZE(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
|
||||
|
||||
#define __unused__ __attribute__ ((unused))
|
||||
|
||||
|
||||
/* Clock frequency Hz. */
|
||||
#define F_CPU 8000000
|
||||
|
||||
|
||||
/* LED matrix columns. */
|
||||
#define LEDMAT_COL1_PIO PIO_DEFINE(PORT_C, 6)
|
||||
#define LEDMAT_COL2_PIO PIO_DEFINE(PORT_B, 7)
|
||||
#define LEDMAT_COL3_PIO PIO_DEFINE(PORT_C, 4)
|
||||
#define LEDMAT_COL4_PIO PIO_DEFINE(PORT_C, 7)
|
||||
#define LEDMAT_COL5_PIO PIO_DEFINE(PORT_C, 5)
|
||||
#define LEDMAT_COLS_NUM 5
|
||||
|
||||
|
||||
/* LED matrix rows. */
|
||||
#define LEDMAT_ROW1_PIO PIO_DEFINE(PORT_B, 6)
|
||||
#define LEDMAT_ROW2_PIO PIO_DEFINE(PORT_B, 5)
|
||||
#define LEDMAT_ROW3_PIO PIO_DEFINE(PORT_B, 4)
|
||||
#define LEDMAT_ROW4_PIO PIO_DEFINE(PORT_B, 3)
|
||||
#define LEDMAT_ROW5_PIO PIO_DEFINE(PORT_B, 2)
|
||||
#define LEDMAT_ROW6_PIO PIO_DEFINE(PORT_B, 1)
|
||||
#define LEDMAT_ROW7_PIO PIO_DEFINE(PORT_B, 0)
|
||||
#define LEDMAT_ROWS_NUM 7
|
||||
|
||||
|
||||
/* Button. */
|
||||
#define BUTTON1 0
|
||||
#define BUTTON1_PIO PIO_DEFINE(PORT_D, 7)
|
||||
|
||||
|
||||
/* Navswitch. */
|
||||
#define NAVSWITCH_PUSH_PIO LEDMAT_COL3_PIO
|
||||
#define NAVSWITCH_EAST_PIO LEDMAT_COL1_PIO
|
||||
#define NAVSWITCH_WEST_PIO LEDMAT_COL2_PIO
|
||||
#define NAVSWITCH_NORTH_PIO LEDMAT_COL4_PIO
|
||||
#define NAVSWITCH_SOUTH_PIO LEDMAT_COL5_PIO
|
||||
|
||||
|
||||
/* LED (active high). */
|
||||
#define LED1 0
|
||||
#define LED1_PIO PIO_DEFINE(PORT_C, 2)
|
||||
|
||||
|
||||
/* Infrared transmitter LED and receiver. */
|
||||
#define IR_TX_LOW_PIO PIO_DEFINE(PORT_D, 3)
|
||||
#define IR_TX_HIGH_PIO PIO_DEFINE(PORT_D, 0)
|
||||
#define IR_RX_PIO PIO_DEFINE(PORT_D, 2)
|
||||
|
||||
#define IR_MODULATION_FREQ 36e3
|
||||
|
||||
void system_init (void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/** @file system.h
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 15 May 2007
|
||||
@brief Target specific definitions
|
||||
*/
|
||||
#ifndef TARGET_H
|
||||
#define TARGET_H
|
||||
|
||||
#define F_CPU 8000000
|
||||
|
||||
|
||||
/* LED matrix columns. */
|
||||
#define LEDMAT_COL1_PIO PIO_DEFINE(PORT_C, 5)
|
||||
#define LEDMAT_COL2_PIO PIO_DEFINE(PORT_C, 7)
|
||||
#define LEDMAT_COL3_PIO PIO_DEFINE(PORT_C, 4)
|
||||
#define LEDMAT_COL4_PIO PIO_DEFINE(PORT_B, 7)
|
||||
#define LEDMAT_COL5_PIO PIO_DEFINE(PORT_C, 6)
|
||||
#define LEDMAT_COLS_NUM 5
|
||||
|
||||
|
||||
/* LED matrix rows. */
|
||||
#define LEDMAT_ROW1_PIO PIO_DEFINE(PORT_B, 0)
|
||||
#define LEDMAT_ROW2_PIO PIO_DEFINE(PORT_B, 1)
|
||||
#define LEDMAT_ROW3_PIO PIO_DEFINE(PORT_B, 2)
|
||||
#define LEDMAT_ROW4_PIO PIO_DEFINE(PORT_B, 3)
|
||||
#define LEDMAT_ROW5_PIO PIO_DEFINE(PORT_B, 4)
|
||||
#define LEDMAT_ROW6_PIO PIO_DEFINE(PORT_B, 5)
|
||||
#define LEDMAT_ROW7_PIO PIO_DEFINE(PORT_B, 6)
|
||||
#define LEDMAT_ROWS_NUM 7
|
||||
|
||||
|
||||
/* Button. */
|
||||
#define BUTTON1 0
|
||||
#define BUTTON1_PIO PIO_DEFINE(PORT_D, 7)
|
||||
|
||||
|
||||
/* Navswitch. */
|
||||
#define NAVSWITCH_PUSH_PIO LEDMAT_COL3_PIO
|
||||
#define NAVSWITCH_EAST_PIO LEDMAT_COL1_PIO
|
||||
#define NAVSWITCH_WEST_PIO LEDMAT_COL2_PIO
|
||||
#define NAVSWITCH_NORTH_PIO LEDMAT_COL4_PIO
|
||||
#define NAVSWITCH_SOUTH_PIO LEDMAT_COL5_PIO
|
||||
|
||||
|
||||
/* LED (active high). */
|
||||
#define LED1 0
|
||||
#define LED1_PIO PIO_DEFINE(PORT_C, 2)
|
||||
|
||||
|
||||
/* Infrared transmitter LED and receiver. */
|
||||
#define IR_TX_HIGH_PIO PIO_DEFINE(PORT_D, 3)
|
||||
#define IR_TX_LOW_PIO PIO_DEFINE(PORT_D, 0)
|
||||
#define IR_RX_PIO PIO_DEFINE(PORT_D, 2)
|
||||
|
||||
#define IR_MODULATION_FREQ 36e3
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
/** @file timer.c
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 21 August 2007
|
||||
Description: Support for timer.
|
||||
*/
|
||||
#include "timer.h"
|
||||
#include "unistd.h"
|
||||
#include "time.h"
|
||||
#include "system.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static timer_tick_t offset;
|
||||
|
||||
|
||||
/* Initialise timer. */
|
||||
void timer_init (void)
|
||||
{
|
||||
/* Save offset so timer starts around 0. */
|
||||
offset = timer_get ();
|
||||
}
|
||||
|
||||
|
||||
/** Get current time:
|
||||
@return current time in ticks. */
|
||||
timer_tick_t timer_get (void)
|
||||
{
|
||||
struct timespec time;
|
||||
uint64_t time_us;
|
||||
uint64_t ticks;
|
||||
|
||||
clock_gettime (CLOCK_MONOTONIC, &time);
|
||||
|
||||
time_us = time.tv_sec * 1000000 + time.tv_nsec / 1000;
|
||||
ticks = time_us * TIMER_RATE / 1000000;
|
||||
|
||||
return (timer_tick_t) ticks - offset;
|
||||
}
|
||||
|
||||
|
||||
/** Wait until specified time:
|
||||
@param when time to sleep until
|
||||
@return current time. */
|
||||
timer_tick_t timer_wait_until (timer_tick_t when)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
timer_tick_t diff;
|
||||
timer_tick_t now;
|
||||
|
||||
now = timer_get ();
|
||||
|
||||
diff = now - when;
|
||||
|
||||
/* Allow for 1000 tick overrun. */
|
||||
if (diff < TIMER_OVERRUN_MAX)
|
||||
return now;
|
||||
|
||||
diff = when - now;
|
||||
|
||||
usleep (diff * 1e6 / TIMER_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Wait for specified period:
|
||||
@param period how long to wait
|
||||
@return current time. */
|
||||
timer_tick_t timer_wait (timer_tick_t period)
|
||||
{
|
||||
return timer_wait_until (timer_get () + period);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/** @file timer.h
|
||||
@author M. P. Hayes, UCECE
|
||||
@date 18 August 2011
|
||||
@brief Timer support.
|
||||
|
||||
@defgroup timer Timer module
|
||||
|
||||
This module provides simple timer support by abstracting a
|
||||
hardware timer.
|
||||
|
||||
The rate that the timer is incremented is specified by the
|
||||
macro TIMER_CLOCK_DIVISOR in the header file system.h This
|
||||
must be a value supported by the timer clock prescaler.
|
||||
|
||||
The rate that the timer is incremented can be found using the
|
||||
macro TIMER_RATE.
|
||||
|
||||
The timer is free-running and will increment TIMER_RATE times
|
||||
per second. When the timer reaches 65535 on the next increment
|
||||
it rolls over to 0.
|
||||
|
||||
Here's a simple example for turning an LED on for 0.5 second
|
||||
and then off for 0.75 second.
|
||||
|
||||
@code
|
||||
#include "timer.h"
|
||||
#include "led.h"
|
||||
|
||||
void main (void)
|
||||
{
|
||||
timer_tick_t now;
|
||||
|
||||
system_init ();
|
||||
timer_init ();
|
||||
led_init ();
|
||||
|
||||
now = timer_get ();
|
||||
while (1)
|
||||
{
|
||||
led_set (LED1, 1);
|
||||
|
||||
now = timer_wait_until (now + (timer_tick_t)(TIMER_RATE * 0.5));
|
||||
|
||||
led_set (LED1, 0);
|
||||
|
||||
now = timer_wait_until (now + (timer_tick_t)(TIMER_RATE * 0.75));
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include "system.h"
|
||||
|
||||
|
||||
#ifndef TIMER_CLOCK_DIVISOR
|
||||
#define TIMER_CLOCK_DIVISOR 256
|
||||
#endif
|
||||
|
||||
/** Rate in Hz that the timer is incremented. */
|
||||
#define TIMER_RATE (F_CPU / TIMER_CLOCK_DIVISOR)
|
||||
|
||||
|
||||
/** The maximum overrun (in ticks). */
|
||||
#define TIMER_OVERRUN_MAX 1000
|
||||
|
||||
|
||||
/** The maximum delay (in ticks). */
|
||||
#define TIMER_DELAY_MAX (65536u - TIMER_OVERRUN_MAX)
|
||||
|
||||
|
||||
/** Define timer ticks. */
|
||||
typedef uint16_t timer_tick_t;
|
||||
|
||||
|
||||
/** Get current time:
|
||||
@return current time in ticks. */
|
||||
timer_tick_t timer_get (void);
|
||||
|
||||
|
||||
/** Wait until specified time:
|
||||
@param when time to sleep until
|
||||
@return current time. */
|
||||
timer_tick_t timer_wait_until (timer_tick_t when);
|
||||
|
||||
|
||||
/** Wait for specified period:
|
||||
@param period how long to wait
|
||||
@return current time. */
|
||||
timer_tick_t timer_wait (timer_tick_t period);
|
||||
|
||||
|
||||
/** Initialise timer. */
|
||||
void timer_init (void);
|
||||
|
||||
#endif /* TIMER_H */
|
||||
Reference in New Issue
Block a user