blob: 2893a6cf1cb36c59ac962da33c4ea740bef125b8 (
plain) (
tree)
|
|
/* Copyright (c) 2016, NORDUnet A/S. */
/* See LICENSE.txt for licensing information. */
#include <inttypes.h>
#include <avr/io.h> /* -D__AVR_ATtiny828__ will include <avr/iotn828.h> */
/* Mapping of pins to names. */
#define AVR_LED1 PORTA0
#define AVR_LED2 PORTA3
#define AVR_LED3 PORTA2
#define AVR_LED4 PORTA1
#define AVR_PANIC PORTA4
#define MKM_AVR_CS_N PORTA5
#define MKM_CONTROL_AVR_ENA PORTA6
#define MKM_CONTROL_FPGA_DIS PORTA7
#define MKM_AVR_MOSI PORTD0
#define MKM_AVR_MISO PORTD1
#define MKM_AVR_SCK PORTD3
/* Input pins. */
#define AVR_PANIC_PIN PINA /* Panic button. */
#define AVR_PANIC_BIT PINA4 /* 0 = panic. */
/* Output ports. */
#define AVR_LED_PORT PORTA
#define AVR_LED_BLUE_BIT PORTA0
#define AVR_LED_RED_BIT PORTA3
#define AVR_LED_YELLOW_BIT PORTA2
#define AVR_LED_GREEN_BIT PORTA1
#define MKM_CS_PORT PORTA /* MKM chip select. */
#define MKM_CS_BIT MKM_AVR_CS_N /* 0 -> selected. */
#define MKM_CONTROL_AVR_PORT PORTA /* AVR in control. */
#define MKM_CONTROL_AVR_BIT MKM_CONTROL_AVR_ENA /* 0 -> in control. */
#define MKM_CONTROL_FPGA_PORT PORTA /* FPGA in control. */
#define MKM_CONTROL_FPGA_BIT MKM_CONTROL_FPGA_DIS /* 0 -> in control. */
/* SPI. */
#define MKM_AVR_MOSI_PORT PORTD
#define MKM_AVR_MOSI_BIT MKM_AVR_MOSI /* PD0, Master Out Slave In. */
#define MKM_AVR_MISO_PORT PORTD
#define MKM_AVR_MISO_BIT PORTD1 /* PD1, Master In Slave Out. */
#define MKM_AVR_SCK_PORT PORTD
#define MKM_AVR_SCK_BIT PORTD3 /* PD3, SPI clock. */
/*******/
/* MKM */
static inline void
mkm_chip_select(int select_flag)
{
if (select_flag)
MKM_CS_PORT &= ~_BV(MKM_CS_BIT); /* CS low. */
else
MKM_CS_PORT |= _BV(MKM_CS_BIT); /* CS high. */
}
static inline void
mkm_grab()
{
MKM_CONTROL_FPGA_PORT |= _BV(MKM_CONTROL_FPGA_BIT);
MKM_CONTROL_AVR_PORT &= ~_BV(MKM_CONTROL_AVR_BIT);
}
static inline void
mkm_release()
{
MKM_CONTROL_AVR_PORT |= _BV(MKM_CONTROL_AVR_BIT);
MKM_CONTROL_FPGA_PORT &= ~_BV(MKM_CONTROL_FPGA_BIT);
}
/*******/
/* SPI */
#define SPI_SS DDRC0 /* SPI slave select. */
static inline void
spi_setup(int on_flag)
{
if (on_flag)
{
/* Disable SPI power reduction. */
PRR &= ~_BV(PRSPI);
/* Set MOSI and SCK to output. */
DDRD = _BV(MKM_AVR_MOSI_BIT) | _BV(MKM_AVR_SCK_BIT);
/* Make sure SPI slave select (SS) is configured as output before
enabling SPI master mode!. */
DDRC |= _BV(SPI_SS);
/* Enable SPI in master mode, clock rate f/16. */
SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0);
}
else
{
SPCR &= ~_BV(SPE);
PRR |= _BV(PRSPI);
}
}
/* SPI commands for MKM (23K640). */
#define SPI_READ 0x03
#define SPI_WRITE 0x02
#define SPI_RDSR 0x05 /* Read status register. */
#define SPI_WRSR 0x01 /* Write status register. */
static inline void
spi_write(uint8_t val)
{
/* Move the value to be sent to the SPI slave into the SPI
register. This starts the SPI clock. */
SPDR = val;
/* Wait for the byte to be shifted into the slave. */
loop_until_bit_is_set(SPSR, SPIF);
}
static inline uint8_t
spi_read()
{
/* Start clocking the SPI slave by moving a dummy byte (0) into the
SPI register and wait for the byte from the slave to be shifted
in. */
spi_write(0);
/* Read the SPI register and return the value. */
return SPDR;
}
static inline uint8_t
spi_read_status()
{
spi_write(SPI_RDSR);
return SPDR;
}
static inline void
spi_set_operation_byte()
{
spi_write(SPI_WRSR);
spi_write(0x00);
}
static inline void
spi_set_operation_page()
{
spi_write(SPI_WRSR);
spi_write(0x80);
}
static inline void
spi_set_operation_seq()
{
spi_write(SPI_WRSR);
spi_write(0x40);
}
static void
spi_write_byte(uint16_t addr, uint8_t data)
{
mkm_chip_select(1);
spi_write(SPI_WRITE);
spi_write(addr & 0xff00);
spi_write(addr & 0x00ff);
spi_write(data);
mkm_chip_select(0);
}
static uint8_t
spi_read_byte(uint16_t addr)
{
mkm_chip_select(1);
spi_write(SPI_READ);
spi_write(addr & 0xff00);
spi_write(addr & 0x00ff);
uint8_t data = spi_read();
mkm_chip_select(0);
return data;
}
static inline int
panic_p()
{
return !bit_is_set(AVR_PANIC_PIN, AVR_PANIC_BIT);
}
static inline void
init_ports()
{
/* Configure all PORTA pins except the tamper detection pin to
outputs. */
DDRA = 0xff & ~_BV(AVR_PANIC_BIT);
}
int
main()
{
init_ports();
int i, j = 0, wait;
uint8_t mkm_val = 0;
while (1)
{
if (panic_p())
{
spi_setup(1);
mkm_grab();
spi_write_byte(0, spi_read_byte(0) + 1);
mkm_val = spi_read_byte(0);
AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | (mkm_val & 0x0f);
wait = 32000;
}
else
{
mkm_release();
spi_setup(0);
if ((j++ & 1) == 0)
AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | 0xa;
else
AVR_LED_PORT = (AVR_LED_PORT & 0xf0) | 0x5;
wait = 16000;
}
for (i = 0; i < wait; i++);
}
return 0;
}
|