Skip to content

Commit 4cd9f83

Browse files
authored
Merge pull request #392 from vintagepc/SPI-clock-rates
Clock out SPI data according to SPCR/SPSR
2 parents 1ce3462 + 500b100 commit 4cd9f83

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

simavr/sim/avr_spi.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
avr_spi.c
33
44
Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5+
Modified 2020 by VintagePC <https://github.com/vintagepc> to support clock divisors
56
67
This file is part of simavr.
78
@@ -25,7 +26,7 @@
2526
static avr_cycle_count_t avr_spi_raise(struct avr_t * avr, avr_cycle_count_t when, void * param)
2627
{
2728
avr_spi_t * p = (avr_spi_t *)param;
28-
29+
2930
if (avr_regbit_get(avr, p->spe)) {
3031
// in master mode, any byte is sent as it comes..
3132
if (avr_regbit_get(avr, p->mstr)) {
@@ -48,14 +49,22 @@ static uint8_t avr_spi_read(struct avr_t * avr, avr_io_addr_t addr, void * param
4849

4950
static void avr_spi_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
5051
{
52+
53+
static const uint8_t _avr_spi_clkdiv[4] = {4,16,64,128};
5154
avr_spi_t * p = (avr_spi_t *)param;
5255

5356
if (addr == p->r_spdr) {
5457
/* Clear the SPIF bit. See ATmega164/324/644 manual, Section 18.5.2. */
5558
avr_regbit_clear(avr, p->spi.raised);
5659

5760
avr_core_watch_write(avr, addr, v);
58-
avr_cycle_timer_register_usec(avr, 100, avr_spi_raise, p); // should be speed dependent
61+
uint16_t clock_shift = _avr_spi_clkdiv[avr->data[p->r_spcr]&0b11];
62+
// If master && 2X, double rate (half divisor)
63+
if (avr_regbit_get(avr, p->mstr) && avr_regbit_get(avr, p->spr[2]))
64+
clock_shift>>=1;
65+
66+
// We can wait directly in clockshifts, it is a divisor, so /4 means 4 avr cycles to clock out one bit.
67+
avr_cycle_timer_register(avr, clock_shift<<3, avr_spi_raise, p); // *8 since 8 clocks to a byte.
5968
}
6069
}
6170

@@ -72,7 +81,7 @@ static void avr_spi_irq_input(struct avr_irq_t * irq, uint32_t value, void * par
7281
p->input_data_register = value;
7382
avr_raise_interrupt(avr, &p->spi);
7483

75-
// if in slave mode,
84+
// if in slave mode,
7685
// 'output' the byte only when we received one...
7786
if (!avr_regbit_get(avr, p->mstr)) {
7887
avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]);
@@ -108,4 +117,3 @@ void avr_spi_init(avr_t * avr, avr_spi_t * p)
108117
avr_register_io_write(avr, p->r_spdr, avr_spi_write, p);
109118
avr_register_io_read(avr, p->r_spdr, avr_spi_read, p);
110119
}
111-

simavr/sim/avr_spi.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
avr_spi.h
33
44
Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5+
Modified 2020 by VintagePC <https://github.com/vintagepc> to support clock divisors
56
67
This file is part of simavr.
78
@@ -45,11 +46,11 @@ typedef struct avr_spi_t {
4546
avr_io_addr_t r_spdr; // data register
4647
avr_io_addr_t r_spcr; // control register
4748
avr_io_addr_t r_spsr; // status register
48-
49+
4950
avr_regbit_t spe; // spi enable
5051
avr_regbit_t mstr; // master/slave
5152
avr_regbit_t spr[4]; // clock divider
52-
53+
5354
avr_int_vector_t spi; // spi interrupt
5455

5556
uint8_t input_data_register;

0 commit comments

Comments
 (0)