diff options
| author | dmlunar <root@lunar.sh> | 2025-01-22 16:47:21 +0200 |
|---|---|---|
| committer | dmlunar <root@lunar.sh> | 2025-10-15 23:42:50 +0200 |
| commit | 729f2a2c3ebfb2612d873caf453a1d7ca02180d9 (patch) | |
| tree | 7bab2fcc0c7f50eab3013348697bc06ddd71d551 /firmware/src/peripheral | |
| download | varpa-729f2a2c3ebfb2612d873caf453a1d7ca02180d9.tar.gz varpa-729f2a2c3ebfb2612d873caf453a1d7ca02180d9.zip | |
varpa: initial public commit
Diffstat (limited to 'firmware/src/peripheral')
| -rw-r--r-- | firmware/src/peripheral/ring.c | 115 | ||||
| -rw-r--r-- | firmware/src/peripheral/spi.c | 106 | ||||
| -rw-r--r-- | firmware/src/peripheral/timer.c | 57 | ||||
| -rw-r--r-- | firmware/src/peripheral/twi.c | 114 | ||||
| -rw-r--r-- | firmware/src/peripheral/uart.c | 239 |
5 files changed, 631 insertions, 0 deletions
diff --git a/firmware/src/peripheral/ring.c b/firmware/src/peripheral/ring.c new file mode 100644 index 0000000..eacb654 --- /dev/null +++ b/firmware/src/peripheral/ring.c @@ -0,0 +1,115 @@ +/** + * + * Author: Dylan Muller + * Copyright (c) 2025 + * All rights reserved. + * + * - Commercial/IP use prohibited. + * - Attribution required. + * See License.txt + * + */ + +#include "peripheral/ring.h" + +#define RING_INC_ROLL_OVER(n, s, e) (((n)+1>=(e)) ? (s) : (n)+1) + +ring_t ring_init( + uint8_t *buf, + size_t len +) +{ + return RING_INIT(buf, len); +} + +bool ring_is_empty( + ring_t ring +) +{ + return ring.read == ring.write; +} + +bool ring_is_full( + ring_t ring +) +{ + return RING_INC_ROLL_OVER(ring.write, ring.buf, ring.end) == ring.read; +} + +size_t ring_push_available( + ring_t ring +) +{ + if(ring.write < ring.read) + return ring.read - ring.write - 1; + else + return (ring.end - ring.buf) - (ring.write - ring.read) - 1; +} + +size_t ring_pop_available( + ring_t ring +) +{ + if(ring.read <= ring.write) + return ring.write - ring.read; + else + return (ring.end - ring.buf) - (ring.read - ring.write); +} + +bool ring_push( + ring_t *ring, + uint8_t data +) +{ + if(ring_is_full(*ring)) + return 1; + + *ring->write = data; + ring->write = RING_INC_ROLL_OVER(ring->write, ring->buf, ring->end); + + return 0; +} + +bool ring_push_over( + ring_t *ring, + uint8_t data +) +{ + *ring->write = data; + ring->write = RING_INC_ROLL_OVER(ring->write, ring->buf, ring->end); + + if(ring->read == ring->write) + { + ring->read = RING_INC_ROLL_OVER(ring->read, ring->buf, ring->end); + return 1; + } + + return 0; +} + +bool ring_pop( + ring_t *ring, + uint8_t *data +) +{ + if(ring_is_empty(*ring)) + return 1; + + *data = *ring->read; + ring->read = RING_INC_ROLL_OVER(ring->read, ring->buf, ring->end); + + return 0; +} + +bool ring_peek( + ring_t *ring, + uint8_t *data +) +{ + if(ring_is_empty(*ring)) + return 1; + + *data = *ring->read; + + return 0; +} diff --git a/firmware/src/peripheral/spi.c b/firmware/src/peripheral/spi.c new file mode 100644 index 0000000..884985d --- /dev/null +++ b/firmware/src/peripheral/spi.c @@ -0,0 +1,106 @@ +/** + * + * Author: Dylan Muller + * Copyright (c) 2025 + * All rights reserved. + * + * - Commercial/IP use prohibited. + * - Attribution required. + * See License.txt + * + */ + +#include "setup.h" + +#include "peripheral/spi.h" + +#include <stdio.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> + +#if SPI_MODE == 0 + #define CPOL_VALUE 0 + #define CPHA_VALUE 0 +#elif SPI_MODE == 1 + #define CPOL_VALUE 0 + #define CPHA_VALUE 1 +#elif SPI_MODE == 2 + #define CPOL_VALUE 1 + #define CPHA_VALUE 0 +#elif SPI_MODE == 3 + #define CPOL_VALUE 1 + #define CPHA_VALUE 1 +#else + #error "No valid SPI_MODE defined!" +#endif + +#if SPI_DORD == 0 + #define DORD_VALUE 0 +#elif SPI_DORD == 1 + #define DORD_VALUE 1 +#else + #error "No valid SPI_DORD defined!" +#endif + +static volatile uint8_t *spi_out; +static volatile uint8_t *spi_in; +static volatile size_t spi_len; +static volatile uint8_t *spi_port; +static volatile uint8_t spi_pin; + +void spi_init(void) +{ + DDRB |= (1 << DDB2) | (1 << DDB3) | (1 << DDB5); + + SPSR |= (SPI2X_VALUE << SPI2X); + SPCR |= (1 << SPIE) | (1 << SPE) | (DORD_VALUE << DORD) | (1 << MSTR) + | (CPOL_VALUE << CPOL) | (CPHA_VALUE << CPHA) + | (SPR1_VALUE << SPR1) | (SPR0_VALUE << SPR0); +} + +bool spi_busy(void) +{ + return spi_len; +} + +void spi_flush(void) +{ + while(spi_len); +} + +void spi_start( + uint8_t *out, + uint8_t *in, + size_t len, + uint8_t *port, + uint8_t pin +) +{ + spi_flush(); + + spi_out = out; + spi_in = in; + spi_len = len; + spi_port = port; + spi_pin = pin; + + if(spi_port) + *spi_port &= ~(1 << spi_pin); + + SPDR = *spi_out++; +} + +ISR(SPI_STC_vect) +{ + if(spi_in) + { + *spi_in++ = SPDR; + } + + if(--spi_len) + SPDR = *spi_out++; + else + if(spi_port) + *spi_port |= (1 << spi_pin); +} diff --git a/firmware/src/peripheral/timer.c b/firmware/src/peripheral/timer.c new file mode 100644 index 0000000..1caff1c --- /dev/null +++ b/firmware/src/peripheral/timer.c @@ -0,0 +1,57 @@ +/** + * + * Author: Dylan Muller + * Copyright (c) 2025 + * All rights reserved. + * + * - Commercial/IP use prohibited. + * - Attribution required. + * See License.txt + * + */ + +#include "setup.h" + +#include "peripheral/timer.h" + +#include <stdint.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/atomic.h> + +uint32_t millis_count = 0; + +void timer_init(void) +{ + uint32_t ctc_overflow; + + ctc_overflow = ((F_CPU / 1000) / 8); + TCCR1B |= (1 << WGM12) | (1 << CS11); + + OCR1AH = (ctc_overflow >> 8); + OCR1AL = ctc_overflow; + + TIMSK1 |= (1 << OCIE1A); +} + +void timer_reset(void) +{ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + millis_count = 0; + } +} + +uint32_t timer_millis(void) +{ + uint32_t millis; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + millis = millis_count; + } + return millis; +} + +ISR(TIMER1_COMPA_vect) +{ + millis_count++; +} diff --git a/firmware/src/peripheral/twi.c b/firmware/src/peripheral/twi.c new file mode 100644 index 0000000..671490b --- /dev/null +++ b/firmware/src/peripheral/twi.c @@ -0,0 +1,114 @@ +/** + * + * Author: Dylan Muller + * Copyright (c) 2025 + * All rights reserved. + * + * - Commercial/IP use prohibited. + * - Attribution required. + * See License.txt + * + */ + +#include "setup.h" + +#include "peripheral/twi.h" + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include <util/twi.h> + +#define TWBR_VALUE ((F_CPU/TWI_FREQUENCY - 16) / (2 * TWI_PRESCALER)) + +static uint8_t twi_address; +static uint8_t* twi_data; +static size_t twi_index; +static size_t twi_len; + +void twi_init(void) +{ + TWBR = TWBR_VALUE; + TWSR = (TWPS1_VALUE << TWPS1) | (TWPS0_VALUE << TWPS0); + + TWCR = (1 << TWINT) | (1 << TWEN); +} + +bool twi_busy(void) +{ + return TWCR & (1<<TWIE); +} + +void twi_flush(void) +{ + while(TWCR & (1<<TWIE)); +} + +void twi_start( + uint8_t address, + uint8_t *data, + size_t len +) +{ + twi_flush(); + + twi_address = address; + twi_data = data; + twi_len = len; + + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE); +} + +ISR(TWI_vect) +{ + switch(TW_STATUS) + { + case TW_START: + case TW_REP_START: + twi_index = 0; + TWDR = twi_address; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); + break; + + case TW_MT_SLA_ACK: + case TW_MT_DATA_ACK: + if(twi_index < twi_len) + { + TWDR = twi_data[twi_index++]; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); + } + else + { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + } + break; + + case TW_MR_DATA_ACK: + twi_data[twi_index++] = TWDR; + case TW_MR_SLA_ACK: + if(twi_index < twi_len-1) + { + TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE); + } + else + { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE); + } + break; + + case TW_MR_DATA_NACK: + twi_data[twi_index++] = TWDR; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + break; + + case TW_MT_ARB_LOST: + TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE); + break; + + case TW_MT_SLA_NACK: + case TW_MT_DATA_NACK: + case TW_MR_SLA_NACK: + default: + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); + } +} diff --git a/firmware/src/peripheral/uart.c b/firmware/src/peripheral/uart.c new file mode 100644 index 0000000..defcf54 --- /dev/null +++ b/firmware/src/peripheral/uart.c @@ -0,0 +1,239 @@ +/** + * + * Author: Dylan Muller + * Copyright (c) 2025 + * All rights reserved. + * + * - Commercial/IP use prohibited. + * - Attribution required. + * See License.txt + * + */ + +#include "setup.h" + +#include "peripheral/ring.h" +#include "peripheral/uart.h" + +#include "status.h" +#include "cmd.h" + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/atomic.h> +#include <util/setbaud.h> + +extern t_system_status system_status; + +static int uart_putc( + char c, + FILE *stream +) +{ + (void)stream; + + if(uart_tx(c)) + return _FDEV_EOF; + + return c; +} + +static int uart_getc( + FILE *stream +) +{ + uint8_t c; + (void)stream; + + if(uart_rx(&c)) + return _FDEV_EOF; + + return c; +} + +FILE uart_out = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE); +FILE uart_in = FDEV_SETUP_STREAM(NULL, uart_getc, _FDEV_SETUP_READ); + +static volatile ring_t uart_tx_ring; +static volatile ring_t uart_rx_ring; + +static volatile uint8_t uart_tx_buf[UART_BUF_SIZE]; +static volatile uint8_t uart_rx_buf[UART_BUF_SIZE]; + +void uart_init(void) +{ + uart_tx_ring = ring_init((uint8_t*)uart_tx_buf, UART_BUF_SIZE - 1); + uart_rx_ring = ring_init((uint8_t*)uart_rx_buf, UART_BUF_SIZE - 1); + + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + UCSR0B |= (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); + + stdout = &uart_out; + stdin = &uart_in; +} + +bool uart_tx( + uint8_t data +) +{ + bool ret; + + while(ring_is_full(uart_tx_ring)); + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + ret = ring_push((ring_t*)&uart_tx_ring, data); + } + + if(!ret) + UCSR0B |= (1 << UDRIE0); + + return ret; +} + +bool uart_rx( + uint8_t* data +) +{ + bool ret; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + ret = ring_pop((ring_t*)&uart_rx_ring, data); + } + + return ret; +} + +size_t uart_tx_burst( + uint8_t *data, + size_t size +) +{ + size_t i = 0; + + while(i<size && !uart_tx(*data++)) + i++; + + return i; +} + +size_t uart_rx_burst( + uint8_t* data, + size_t len +) +{ + size_t i = 0; + + while(i<len && !uart_rx(data++)) + i++; + + return i; +} + +size_t uart_tx_available(void) +{ + size_t ret; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + ret = ring_push_available(uart_tx_ring); + } + + return ret; +} + +size_t uart_rx_available(void) +{ + size_t ret; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + ret = ring_pop_available(uart_rx_ring); + } + + return ret; +} + +bool uart_rx_peek( + uint8_t *data +) +{ + bool ret; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + ret = ring_peek((ring_t*)&uart_rx_ring, data); + } + + return ret; +} + +void uart_tx_flush(void) +{ + bool empty; + do + { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + empty = ring_is_empty(uart_tx_ring); + } + } while(!empty); +} + +char *uart_ngets(char *s, size_t n) +{ + uint8_t c; + static size_t i = 0; + + + while(!uart_rx(&c)) + { + s[i++] = c; + + if(c == '\n' || i >= n-1) + { + s[i] = '\0'; + i = 0; + + return s; + } + } + + return NULL; +} + +ISR(USART_UDRE_vect) +{ + uint8_t c; + + if(!ring_pop((ring_t*)&uart_tx_ring, &c)) + UDR0 = c; + + else + UCSR0B &= ~(1 << UDRIE0); +} + +ISR(USART_RX_vect) +{ + if (system_status.status == SYSTEM_STATUS_BUSY) + { + // system busy.. lock now! + CMD_ERROR("SYSTEM BUSY"); + system_status.status = SYSTEM_STATUS_LOCKED; + } + + if (system_status.status != SYSTEM_STATUS_LOCKED) + { + #ifdef UART_OVERWRITE + ring_push_over((ring_t*)&uart_rx_ring, UDR0); + #else + ring_push((ring_t*)&uart_rx_ring, UDR0); + #endif + } + else{ + (uint8_t)UDR0; + } +} |
