aboutsummaryrefslogtreecommitdiff
path: root/drivers/avr/spi_master.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/avr/spi_master.c')
-rw-r--r--drivers/avr/spi_master.c123
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
37static pin_t currentSlavePin = NO_PIN; 41static pin_t currentSlavePin = NO_PIN;
38static uint8_t currentSlaveConfig = 0; 42static uint8_t currentSlaveConfig = 0;
39static bool currentSlave2X = false; 43static 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
50void spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint8_t divisor) { 54bool 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
103spi_status_t spi_write(uint8_t data, uint16_t timeout) { 116spi_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
116spi_status_t spi_read(uint16_t timeout) { 129spi_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
129spi_status_t spi_transmit(const uint8_t *data, uint16_t length, uint16_t timeout) { 142spi_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
139spi_status_t spi_receive(uint8_t *data, uint16_t length, uint16_t timeout) { 152spi_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}