avr_spi.c
Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+ Modified 2020 by VintagePC <https://github.com/vintagepc> to support clock divisors
This file is part of simavr.
static avr_cycle_count_t avr_spi_raise(struct avr_t * avr, avr_cycle_count_t when, void * param)
{
avr_spi_t * p = (avr_spi_t *)param;
-
+
if (avr_regbit_get(avr, p->spe)) {
// in master mode, any byte is sent as it comes..
if (avr_regbit_get(avr, p->mstr)) {
avr_regbit_clear(avr, p->spi.raised);
avr_core_watch_write(avr, addr, v);
- avr_cycle_timer_register_usec(avr, 100, avr_spi_raise, p); // should be speed dependent
+ uint16_t uiClkShift = _avr_spi_clkdiv[avr->data[p->r_spcr]&0b11];
+ // If master && 2X, double rate (half divisor)
+ if (avr_regbit_get(avr, p->mstr) && avr_regbit_get(avr, p->spr[2]))
+ uiClkShift>>=1;
+
+ // We can wait directly in clockshifts, it is a divisor, so /4 means 4 avr cycles to clock out one bit.
+ avr_cycle_timer_register(avr, uiClkShift<<3, avr_spi_raise, p); // *8 since 8 clocks to a byte.
}
}
p->input_data_register = value;
avr_raise_interrupt(avr, &p->spi);
- // if in slave mode,
+ // if in slave mode,
// 'output' the byte only when we received one...
if (!avr_regbit_get(avr, p->mstr)) {
avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]);
avr_register_io_write(avr, p->r_spdr, avr_spi_write, p);
avr_register_io_read(avr, p->r_spdr, avr_spi_read, p);
}
-
avr_spi.h
Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+ Modified 2020 by VintagePC <https://github.com/vintagepc> to support clock divisors
This file is part of simavr.
avr_io_addr_t r_spdr; // data register
avr_io_addr_t r_spcr; // control register
avr_io_addr_t r_spsr; // status register
-
+
avr_regbit_t spe; // spi enable
avr_regbit_t mstr; // master/slave
avr_regbit_t spr[4]; // clock divider
-
+
avr_int_vector_t spi; // spi interrupt
uint8_t input_data_register;
};
#endif
+static const uint8_t _avr_spi_clkdiv[4] = {4,16,64,128};
+
#endif /*__AVR_SPI_H__*/