diff options
Diffstat (limited to 'drivers/avr/spi_master.c')
-rw-r--r-- | drivers/avr/spi_master.c | 123 |
1 files changed, 68 insertions, 55 deletions
diff --git a/drivers/avr/spi_master.c b/drivers/avr/spi_master.c index 3f405ddf5..32cc55c83 100644 --- a/drivers/avr/spi_master.c +++ b/drivers/avr/spi_master.c | |||
@@ -34,6 +34,10 @@ | |||
34 | # define SPI_MISO_PIN B4 | 34 | # define SPI_MISO_PIN B4 |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #ifndef SPI_TIMEOUT | ||
38 | # define SPI_TIMEOUT 100 | ||
39 | #endif | ||
40 | |||
37 | static pin_t currentSlavePin = NO_PIN; | 41 | static pin_t currentSlavePin = NO_PIN; |
38 | static uint8_t currentSlaveConfig = 0; | 42 | static uint8_t currentSlaveConfig = 0; |
39 | static bool currentSlave2X = false; | 43 | static bool currentSlave2X = false; |
@@ -47,65 +51,74 @@ void spi_init(void) { | |||
47 | SPCR = (_BV(SPE) | _BV(MSTR)); | 51 | SPCR = (_BV(SPE) | _BV(MSTR)); |
48 | } | 52 | } |
49 | 53 | ||
50 | void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor) { | 54 | bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { |
51 | if (currentSlavePin == NO_PIN && slavePin != NO_PIN) { | 55 | if (currentSlavePin != NO_PIN || slavePin == NO_PIN) { |
52 | if (lsbFirst) { | 56 | return false; |
53 | currentSlaveConfig |= _BV(DORD); | 57 | } |
54 | } | ||
55 | 58 | ||
56 | switch (mode) { | 59 | currentSlaveConfig = 0; |
57 | case 1: | ||
58 | currentSlaveConfig |= _BV(CPHA); | ||
59 | break; | ||
60 | case 2: | ||
61 | currentSlaveConfig |= _BV(CPOL); | ||
62 | break; | ||
63 | case 3: | ||
64 | currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA)); | ||
65 | break; | ||
66 | } | ||
67 | 60 | ||
68 | uint8_t roundedDivisor = 1; | 61 | if (lsbFirst) { |
69 | while (roundedDivisor < divisor) { | 62 | currentSlaveConfig |= _BV(DORD); |
70 | roundedDivisor <<= 1; | 63 | } |
71 | } | ||
72 | 64 | ||
73 | switch (roundedDivisor) { | 65 | switch (mode) { |
74 | case 16: | 66 | case 1: |
75 | currentSlaveConfig |= _BV(SPR0); | 67 | currentSlaveConfig |= _BV(CPHA); |
76 | break; | 68 | break; |
77 | case 64: | 69 | case 2: |
78 | currentSlaveConfig |= _BV(SPR1); | 70 | currentSlaveConfig |= _BV(CPOL); |
79 | break; | 71 | break; |
80 | case 128: | 72 | case 3: |
81 | currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0)); | 73 | currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA)); |
82 | break; | 74 | break; |
83 | case 2: | 75 | } |
84 | currentSlave2X = true; | ||
85 | break; | ||
86 | case 8: | ||
87 | currentSlave2X = true; | ||
88 | currentSlaveConfig |= _BV(SPR0); | ||
89 | break; | ||
90 | case 32: | ||
91 | currentSlave2X = true; | ||
92 | currentSlaveConfig |= _BV(SPR1); | ||
93 | break; | ||
94 | } | ||
95 | 76 | ||
96 | SPSR |= currentSlaveConfig; | 77 | uint16_t roundedDivisor = 1; |
97 | currentSlavePin = slavePin; | 78 | while (roundedDivisor < divisor) { |
98 | setPinOutput(currentSlavePin); | 79 | roundedDivisor <<= 1; |
99 | writePinLow(currentSlavePin); | 80 | } |
81 | |||
82 | switch (roundedDivisor) { | ||
83 | case 16: | ||
84 | currentSlaveConfig |= _BV(SPR0); | ||
85 | break; | ||
86 | case 64: | ||
87 | currentSlaveConfig |= _BV(SPR1); | ||
88 | break; | ||
89 | case 128: | ||
90 | currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0)); | ||
91 | break; | ||
92 | case 2: | ||
93 | currentSlave2X = true; | ||
94 | break; | ||
95 | case 8: | ||
96 | currentSlave2X = true; | ||
97 | currentSlaveConfig |= _BV(SPR0); | ||
98 | break; | ||
99 | case 32: | ||
100 | currentSlave2X = true; | ||
101 | currentSlaveConfig |= _BV(SPR1); | ||
102 | break; | ||
100 | } | 103 | } |
104 | |||
105 | SPCR |= currentSlaveConfig; | ||
106 | if (currentSlave2X) { | ||
107 | SPSR |= _BV(SPI2X); | ||
108 | } | ||
109 | currentSlavePin = slavePin; | ||
110 | setPinOutput(currentSlavePin); | ||
111 | writePinLow(currentSlavePin); | ||
112 | |||
113 | return true; | ||
101 | } | 114 | } |
102 | 115 | ||
103 | spi_status_t spi_write(uint8_t data, uint16_t timeout) { | 116 | spi_status_t spi_write(uint8_t data) { |
104 | SPDR = data; | 117 | SPDR = data; |
105 | 118 | ||
106 | uint16_t timeout_timer = timer_read(); | 119 | uint16_t timeout_timer = timer_read(); |
107 | while (!(SPSR & _BV(SPIF))) { | 120 | while (!(SPSR & _BV(SPIF))) { |
108 | if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { | 121 | if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) { |
109 | return SPI_STATUS_TIMEOUT; | 122 | return SPI_STATUS_TIMEOUT; |
110 | } | 123 | } |
111 | } | 124 | } |
@@ -113,12 +126,12 @@ spi_status_t spi_write(uint8_t data, uint16_t timeout) { | |||
113 | return SPDR; | 126 | return SPDR; |
114 | } | 127 | } |
115 | 128 | ||
116 | spi_status_t spi_read(uint16_t timeout) { | 129 | spi_status_t spi_read() { |
117 | SPDR = 0x00; // Dummy | 130 | SPDR = 0x00; // Dummy |
118 | 131 | ||
119 | uint16_t timeout_timer = timer_read(); | 132 | uint16_t timeout_timer = timer_read(); |
120 | while (!(SPSR & _BV(SPIF))) { | 133 | while (!(SPSR & _BV(SPIF))) { |
121 | if ((timeout != SPI_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { | 134 | if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) { |
122 | return SPI_STATUS_TIMEOUT; | 135 | return SPI_STATUS_TIMEOUT; |
123 | } | 136 | } |
124 | } | 137 | } |
@@ -126,21 +139,21 @@ spi_status_t spi_read(uint16_t timeout) { | |||
126 | return SPDR; | 139 | return SPDR; |
127 | } | 140 | } |
128 | 141 | ||
129 | spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout) { | 142 | spi_status_t spi_transmit(const uint8_t *data, uint16_t length) { |
130 | spi_status_t status = SPI_STATUS_ERROR; | 143 | spi_status_t status = SPI_STATUS_ERROR; |
131 | 144 | ||
132 | for (uint16_t i = 0; i < length; i++) { | 145 | for (uint16_t i = 0; i < length; i++) { |
133 | status = spi_write(data[i], timeout); | 146 | status = spi_write(data[i]); |
134 | } | 147 | } |
135 | 148 | ||
136 | return status; | 149 | return status; |
137 | } | 150 | } |
138 | 151 | ||
139 | spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout) { | 152 | spi_status_t spi_receive(uint8_t *data, uint16_t length) { |
140 | spi_status_t status = SPI_STATUS_ERROR; | 153 | spi_status_t status = SPI_STATUS_ERROR; |
141 | 154 | ||
142 | for (uint16_t i = 0; i < length; i++) { | 155 | for (uint16_t i = 0; i < length; i++) { |
143 | status = spi_read(timeout); | 156 | status = spi_read(); |
144 | 157 | ||
145 | if (status > 0) { | 158 | if (status > 0) { |
146 | data[i] = status; | 159 | data[i] = status; |
@@ -155,9 +168,9 @@ void spi_stop(void) { | |||
155 | setPinOutput(currentSlavePin); | 168 | setPinOutput(currentSlavePin); |
156 | writePinHigh(currentSlavePin); | 169 | writePinHigh(currentSlavePin); |
157 | currentSlavePin = NO_PIN; | 170 | currentSlavePin = NO_PIN; |
171 | SPSR &= ~(_BV(SPI2X)); | ||
158 | SPCR &= ~(currentSlaveConfig); | 172 | SPCR &= ~(currentSlaveConfig); |
159 | currentSlaveConfig = 0; | 173 | currentSlaveConfig = 0; |
160 | SPSR = 0; | ||
161 | currentSlave2X = false; | 174 | currentSlave2X = false; |
162 | } | 175 | } |
163 | } | 176 | } |