summaryrefslogtreecommitdiff
path: root/firmware/src/peripheral
diff options
context:
space:
mode:
authordmlunar <root@lunar.sh>2025-01-22 16:47:21 +0200
committerdmlunar <root@lunar.sh>2025-10-15 23:42:50 +0200
commit729f2a2c3ebfb2612d873caf453a1d7ca02180d9 (patch)
tree7bab2fcc0c7f50eab3013348697bc06ddd71d551 /firmware/src/peripheral
downloadvarpa-729f2a2c3ebfb2612d873caf453a1d7ca02180d9.tar.gz
varpa-729f2a2c3ebfb2612d873caf453a1d7ca02180d9.zip
varpa: initial public commit
Diffstat (limited to 'firmware/src/peripheral')
-rw-r--r--firmware/src/peripheral/ring.c115
-rw-r--r--firmware/src/peripheral/spi.c106
-rw-r--r--firmware/src/peripheral/timer.c57
-rw-r--r--firmware/src/peripheral/twi.c114
-rw-r--r--firmware/src/peripheral/uart.c239
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;
+ }
+}