Added SPI support file

pull/1/head
Ondřej Hruška 9 years ago
parent 51ea651205
commit 312adbe56c
  1. 1
      Makefile
  2. 7
      avr-c-bp.pro
  3. 32
      lib/calc.h
  4. 62
      lib/spi.c
  5. 69
      lib/spi.h
  6. 2
      lib/usart.c
  7. 26
      lib/usart.h
  8. 2
      main.c

@ -28,6 +28,7 @@ BINARY = main
OBJS = $(BINARY).o
OBJS += lib/usart.o
OBJS += lib/iopins.o
OBJS += lib/spi.o
# Dirs with header files
INCL_DIRS = . lib/

@ -18,12 +18,15 @@ DISTFILES += \
HEADERS += \
lib/calc.h \
lib/iopins.h \
lib/usart.h
lib/usart.h \
lib/nsdelay.h \
lib/spi.h
SOURCES += \
lib/iopins.c \
main.c \
lib/usart.c
lib/usart.c \
lib/spi.c
# === Flags for the Clang code model===
#

@ -10,7 +10,7 @@
// --- Increment in range ---
// when overflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define inc_wrap(var, min, max) { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } }
#define inc_wrap(var, min, max) do { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } } while(0)
// ..., upper bound included
#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1)
@ -18,7 +18,7 @@
// --- Decrement in range ---
// when underflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define dec_wrap(var, min, max) { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } }
#define dec_wrap(var, min, max) do { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } } while(0)
// ..., upper bound included
#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1)
@ -26,31 +26,31 @@
// --- Bit manipulation --
// Set bit
#define sbi(reg, bit) { (reg) |= (1 << (uint8_t)(bit)); }
#define sbi(reg, bit) do { (reg) |= (1 << (uint8_t)(bit)); } while(0)
// Clear bit
#define cbi(reg, bit) { (reg) &= ~(1 << (uint8_t)(bit)); }
#define cbi(reg, bit) do { (reg) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit
#define get_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
#define get_bit(reg, bit) ((bool)((reg) >> (uint8_t)(bit)))
// Test n-th bit (Can't use bit_is_set, as it's redefined in sfr_def.h)
// Test n-th bit (Can't use bit_is_set, as it's defined in sfr_def.h)
#define bit_is_high(reg, bit) get_bit(reg, bit)
#define bit_is_low(reg, bit) (!get_bit(reg, bit))
// Write value to n-th bit
#define set_bit(reg, bit, value) { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
#define set_bit(reg, bit, value) do { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(bool)(value)) << (uint8_t)(bit)); } while(0)
// Invert n-th bit
#define toggle_bit(reg, bit) { (reg) ^= (1 << (uint8_t)(bit)); }
#define toggle_bit(reg, bit) do { (reg) ^= (1 << (uint8_t)(bit)); } while(0)
// --- Bit manipulation with pointer to variable ---
// Set n-th bit in pointee
#define sbi_p(reg_p, bit) { (*(reg_p)) |= (1 << (uint8_t)(bit)); }
#define sbi_p(reg_p, bit) do { (*(reg_p)) |= (1 << (uint8_t)(bit)); } while(0)
// Clear n-th bit in pointee
#define cbi_p(reg_p, bit) { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); }
#define cbi_p(reg_p, bit) do { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); } while(0)
// Get n-th bit in pointee
#define get_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
@ -60,18 +60,18 @@
#define bit_is_low_p(reg_p, bit) (!get_bit_p(reg_p, bit))
// Write value to a bit in pointee
#define set_bit_p(reg_p, bit, value) { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
#define toggle_bit_p(reg_p, bit) { *(reg_p) ^= (1 << (uint8_t)(bit)); }
#define set_bit_p(reg_p, bit, value) do { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bool)(bit)))) | (((uint8_t)(bool)(value)) << (uint8_t)(bit)); } while(0)
#define toggle_bit_p(reg_p, bit) do { *(reg_p) ^= (1 << (uint8_t)(bit)); } while(0)
// --- Nibble manipulation ---
// Replace nibble in a byte
#define set_low_nibble(reg, value) { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble(reg, value) { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define set_low_nibble(reg, value) do { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define set_high_nibble(reg, value) do { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define set_low_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define set_low_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define set_high_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define low_nibble(x) ((uint8_t)(x) & 0xF)
#define high_nibble(x) (((uint8_t)(x) & 0xF0) >> 4)

@ -0,0 +1,62 @@
#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
/** Init SPI (for SD card communication) */
void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv)
{
as_output(PIN_SS); // SS output - we control slave
as_output(PIN_MOSI); // MOSI output - we talk to slave
as_output(PIN_SCK); // SCK output - we're generating clock
// MISO is configured automatically as input
SPCR = 0;
SPCR |= (1 << MSTR);
SPCR |= (order << DORD);
SPCR |= (cpol << CPOL);
SPCR |= (cpha << CPHA);
// speed
SPCR |= (clkdiv & 0b11);
SPSR = (bool)(clkdiv & 0b100); // write SPI2X flag
// enable SPI
SPCR |= (1 << SPE);
}
/** Init SPI (for SD card communication) */
void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha)
{
as_output(PIN_MISO); // we're listening to master
// MOSI, SS, SCK are configured automatically
SPCR = 0;
SPCR |= (order << DORD);
SPCR |= (cpol << CPOL);
SPCR |= (cpha << CPHA);
// enable SPI
SPCR |= (1 << SPE);
}
/** Write a byte to SPI. Returns received byte. */
uint8_t spi_send(uint8_t byte)
{
SPDR = byte;
while (bit_is_low(SPSR, SPIF));
return SPDR;
}
/** Receive (as slave). Blocking. */
uint8_t spi_receive(uint8_t reply)
{
SPDR = reply;
while (bit_is_low(SPSR, SPIF));
return SPDR;
}

@ -0,0 +1,69 @@
#pragma once
#include <avr/io.h>
#include <stdint.h>
#include "calc.h"
#include "iopins.h"
#define PIN_MISO 12
#define PIN_MOSI 11
#define PIN_SCK 13
#define PIN_SS 10
/** Bit order */
enum SPI_order {
SPI_LSB_FIRST = 0,
SPI_MSB_FIRST = 1
};
/** Clock polarity */
enum SPI_cpol {
CPOL_0 = 0,
CPOL_1 = 1
};
/** Clock phase */
enum SPI_cpha {
CPHA_0 = 0,
CPHA_1 = 1
};
/** Clock prescaller <SPI2X><SPR1><SPR0> */
enum SPI_clk_div {
SPI_DIV_2 = 0b100, // 2x (master only, can't receive at this speed)
SPI_DIV_4 = 0b000,
SPI_DIV_8 = 0b101, // 2x
SPI_DIV_16 = 0b001,
SPI_DIV_32 = 0b110, // 2x
SPI_DIV_64 = 0b010,
SPI_DIV_128 = 0b011
};
/** Set SS to active state (LOW) */
#define spi_ss_enable() pin_down(PIN_SS)
/** Set SS to disabled state (HIGH) */
#define spi_ss_disable() pin_up(PIN_SS)
/** Enable SPI ISR */
#define spi_isr_enable(yes) set_bit(SPCR, SPIE, yes)
/** Init SPI (for SD card communication) */
void spi_init_master(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha, enum SPI_clk_div clkdiv);
/** Init SPI (for SD card communication) */
void spi_init_slave(enum SPI_order order, enum SPI_cpol cpol, enum SPI_cpha cpha);
/** Write a byte to SPI. Returns received byte. */
uint8_t spi_send(uint8_t byte);
/** Receive (as slave). Blocking. */
uint8_t spi_receive(uint8_t reply);

@ -66,7 +66,7 @@ void usart_puts_P(const char* str)
/** Clear receive buffer */
void usart_clear_rx(void)
void usart_flush_rx(void)
{
uint8_t dummy;
while (bit_is_high(UCSR0A, RXC0))

@ -32,28 +32,28 @@ enum {
BAUD_1M = 0,
};
/** Init UART with a UBRR value */
/** Init UART with a UBRR value - can use the BAUD_* constants for 16 MHz */
void usart_init(uint16_t ubrr);
/** Check if there's a byte in the RX register */
#define usart_rx_ready() (0 != (UCSR0A & (1 << RXC0)))
#define usart_rx_ready() bit_is_high(UCSR0A, RXC0)
/** Check if transmission of everything is done */
#define usart_tx_ready() (0 != (UCSR0A & (1 << UDRE0)))
/** Check if USART is ready to accept new byte to send */
#define usart_tx_ready() bit_is_low(UCSR0A, UDRE0)
// ---- Enable UART interrupts ------------
/** Enable or disable RX ISR */
#define usart_rx_isr_enable(yes) set_bit(UCSR0B, RXCIE0, (yes))
#define usart_isr_rx_enable(yes) set_bit(UCSR0B, RXCIE0, (yes))
/** Enable or disable TX ISR (1 byte is sent) */
#define usart_tx_isr_enable(yes) set_bit(UCSR0B, TXCIE0, (yes))
/** Enable or disable TX ISR (all data sent) */
#define usart_isr_tx_enable(yes) set_bit(UCSR0B, TXCIE0, (yes))
/** Enable or disable DRE ISR (all is sent) */
#define usart_dre_isr_enable(yes) set_bit(UCSR0B, UDRIE0, (yes))
/** Enable or disable DRE ISR (data register empty) */
#define usart_isr_dre_enable(yes) set_bit(UCSR0B, UDRIE0, (yes))
// ---- Basic IO --------------------------
@ -66,12 +66,8 @@ void usart_tx(uint8_t data);
uint8_t usart_rx(void);
/** Send byte over UART */
#define usart_putc(data) usart_tx((data))
/** Clear receive buffer */
void usart_clear_rx(void);
void usart_flush_rx(void);
// ---- Strings ---------------------------
@ -80,5 +76,5 @@ void usart_clear_rx(void);
void usart_puts(const char* str);
/** Send progmem string over UART */
/** Send progmem string `PSTR("foobar")` over UART */
void usart_puts_P(const char* str);

@ -27,7 +27,7 @@ ISR(USART_RX_vect)
void main()
{
usart_init(BAUD_9600);
usart_rx_isr_enable(true); // enable RX interrupt handler
usart_isr_rx_enable(true); // enable RX interrupt handler
// configure pins
as_output(LED);

Loading…
Cancel
Save