123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /*
- * CNC-remote-control
- * SPI primitives
- *
- * Copyright (C) 2011 Michael Buesch <m@bues.ch>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include "spi.h"
- #include <avr/wdt.h>
- #include <avr/interrupt.h>
- #if SPI_HAVE_ASYNC
- static struct spi_async_state {
- uint8_t flags;
- uint8_t wait_ms;
- uint8_t wait_ms_left;
- uint8_t bytes_left;
- const uint8_t *txbuf;
- uint8_t *rxbuf;
- } async_state;
- static void spi_transfer_async(void)
- {
- uint8_t txbyte;
- if (async_state.flags & SPI_ASYNC_TXPROGMEM) {
- const uint8_t PROGPTR *p = (const uint8_t PROGPTR *)async_state.txbuf;
- txbyte = pgm_read_byte(p);
- } else
- txbyte = *async_state.txbuf;
- async_state.txbuf++;
- async_state.bytes_left--;
- mb();
- SPDR = txbyte;
- }
- ISR(SPI_STC_vect)
- {
- uint8_t rxbyte;
- rxbyte = SPDR;
- *async_state.rxbuf = rxbyte;
- async_state.rxbuf++;
- if (async_state.bytes_left) {
- if (async_state.wait_ms)
- async_state.wait_ms_left =
- (uint8_t)(async_state.wait_ms + 1u);
- else
- spi_transfer_async();
- } else {
- SPCR = (uint8_t)(SPCR & ~(1u << SPIE));
- spi_slave_select(0);
- mb();
- async_state.flags = (uint8_t)(async_state.flags & ~SPI_ASYNC_RUNNING);
- spi_async_done();
- }
- }
- void spi_async_start(void *rxbuf, const void *txbuf,
- uint8_t nr_bytes, uint8_t flags, uint8_t wait_ms)
- {
- BUG_ON(ATOMIC_LOAD(async_state.flags) & SPI_ASYNC_RUNNING);
- BUG_ON(!nr_bytes);
- async_state.flags = flags | SPI_ASYNC_RUNNING;
- async_state.bytes_left = nr_bytes;
- async_state.wait_ms = wait_ms;
- async_state.wait_ms_left = 0;
- async_state.txbuf = txbuf;
- async_state.rxbuf = rxbuf;
- mb();
- (void)SPSR; /* clear state */
- (void)SPDR; /* clear state */
- SPCR |= (1 << SPIE);
- spi_slave_select(1);
- spi_transfer_async();
- }
- bool spi_async_running(void)
- {
- return !!(ATOMIC_LOAD(async_state.flags) & SPI_ASYNC_RUNNING);
- }
- void spi_async_ms_tick(void)
- {
- bool send_next = 0;
- irq_disable();
- if (!(async_state.flags & SPI_ASYNC_RUNNING)) {
- irq_enable();
- return;
- }
- if (async_state.wait_ms_left == 0) {
- irq_enable();
- return;
- }
- async_state.wait_ms_left--;
- if (async_state.wait_ms_left == 0)
- send_next = 1;
- irq_enable();
- if (send_next)
- spi_transfer_async();
- }
- #endif /* SPI_HAVE_ASYNC */
- uint8_t spi_transfer_sync(uint8_t tx)
- {
- SPDR = tx;
- while (!(SPSR & (1 << SPIF)));
- return SPDR;
- }
- uint8_t spi_transfer_slowsync(uint8_t tx)
- {
- _delay_ms(10);
- return spi_transfer_sync(tx);
- }
- void spi_lowlevel_exit(void)
- {
- SPCR = 0;
- SPSR = 0;
- SPDR = 0;
- (void)SPSR; /* clear state */
- (void)SPDR; /* clear state */
- DDRB = 0;
- }
- void spi_lowlevel_init(void)
- {
- spi_slave_select(0);
- DDRB = (uint8_t)(DDRB | (1u << 5/*MOSI*/) |
- (1u << 7/*SCK*/) |
- (1u << 4/*SS*/));
- DDRB = (uint8_t)(DDRB & ~(1u << 6/*MISO*/));
- SPI_MASTER_TRANSIRQ_DDR = (uint8_t)(SPI_MASTER_TRANSIRQ_DDR &
- ~(1u << SPI_MASTER_TRANSIRQ_BIT));
- SPI_MASTER_TRANSIRQ_PORT = (uint8_t)(SPI_MASTER_TRANSIRQ_PORT &
- ~(1u << SPI_MASTER_TRANSIRQ_BIT));
- GICR = (uint8_t)(GICR & ~(1u << SPI_MASTER_TRANSIRQ_INT));
- SPCR = (1u << SPE) | (1u << MSTR) |
- (0u << CPOL) | (0u << CPHA) |
- (0u << SPR0) | (1u << SPR1);
- SPSR = 0u;
- long_delay_ms(150);
- (void)SPSR; /* clear state */
- (void)SPDR; /* clear state */
- }
|