/* Copyright (c) 2016, NORDUnet A/S. */ /* See LICENSE.txt for licensing information. */ #include #include /* -D__AVR_ATtiny828__ will include */ /* 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) { SPDR = val; loop_until_bit_is_set(SPSR, SPIF); } static inline uint8_t spi_read() { spi_write(0); 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; }