22
22
#include " SPI.h"
23
23
#include " HardwareSerial.h"
24
24
25
- typedef struct {
26
- uint32_t divider;
27
- union {
28
- uint32_t regValue;
29
- struct {
30
- unsigned regL :6 ;
31
- unsigned regH :6 ;
32
- unsigned regN :6 ;
33
- unsigned regPre :13 ;
34
- unsigned regEQU :1 ;
35
- };
25
+ typedef union {
26
+ uint32_t regValue;
27
+ struct {
28
+ unsigned regL :6 ;
29
+ unsigned regH :6 ;
30
+ unsigned regN :6 ;
31
+ unsigned regPre :13 ;
32
+ unsigned regEQU :1 ;
36
33
};
37
- } spiClockDiv_t;
38
-
39
- // todo find way of calculation for the divider
40
- static const spiClockDiv_t spiClockDiv[] = {
41
- { 0 , (0x80000000 ) }, // /< [0] EQU: 1 Pre: 0 N: 0 H: 0 L: 0 Div: 0 @80Mhz = 80 MHz @160Mhz = 160 MHz
42
- { 2 , (0x00001001 ) }, // /< [1] EQU: 0 Pre: 0 N: 1 H: 0 L: 1 Div: 2 @80Mhz = 40 MHz @160Mhz = 80 MHz
43
- { 4 , (0x00041001 ) }, // /< [2] EQU: 0 Pre: 1 N: 1 H: 0 L: 1 Div: 4 @80Mhz = 20 MHz @160Mhz = 40 MHz
44
- { 6 , (0x000fffc0 ) }, // /< [3] EQU: 0 Pre: 3 N: 63 H: 63 L: 0 Div: 6 @80Mhz = 16 MHz @160Mhz = 32 MHz
45
- { 8 , (0x000c1001 ) }, // /< [4] EQU: 0 Pre: 3 N: 1 H: 0 L: 1 Div: 8 @80Mhz = 10 MHz @160Mhz = 20 MHz
46
- { 10 , (0x00101001 ) }, // /< [5] EQU: 0 Pre: 4 N: 1 H: 0 L: 1 Div: 10 @80Mhz = 8 MHz @160Mhz = 16 MHz
47
- { 16 , (0x001c1001 ) }, // /< [6] EQU: 0 Pre: 7 N: 1 H: 0 L: 1 Div: 16 @80Mhz = 5 MHz @160Mhz = 10 MHz
48
- { 20 , (0x00241001 ) }, // /< [7] EQU: 0 Pre: 9 N: 1 H: 0 L: 1 Div: 20 @80Mhz = 4 MHz @160Mhz = 8 MHz
49
- { 40 , (0x004c1001 ) }, // /< [8] EQU: 0 Pre: 19 N: 1 H: 0 L: 1 Div: 40 @80Mhz = 2 MHz @160Mhz = 4 MHz
50
- { 80 , (0x009c1001 ) }, // /< [9] EQU: 0 Pre: 39 N: 1 H: 0 L: 1 Div: 80 @80Mhz = 1 MHz @160Mhz = 2 MHz
51
- { 160 , (0x013c1001 ) }, // /< [10] EQU: 0 Pre: 79 N: 1 H: 0 L: 1 Div: 160 @80Mhz = 500 KHz @160Mhz = 1 MHz
52
- { 320 , (0x027c1001 ) }, // /< [11] EQU: 0 Pre: 159 N: 1 H: 0 L: 1 Div: 320 @80Mhz = 250 KHz @160Mhz = 500 KHz
53
- { 640 , (0x04fc1001 ) } // /< [12] EQU: 0 Pre: 319 N: 1 H: 0 L: 1 Div: 640 @80Mhz = 125 KHz @160Mhz = 250 KHz
54
- };
55
-
56
-
57
- static const uint8_t spiClockDiv_count = (sizeof (spiClockDiv) / sizeof (spiClockDiv_t));
34
+ } spiClk_t;
58
35
59
36
SPIClass SPI;
60
37
@@ -65,15 +42,10 @@ void SPIClass::begin() {
65
42
pinMode (SCK, SPECIAL); // /< GPIO14
66
43
pinMode (MISO, SPECIAL); // /< GPIO12
67
44
pinMode (MOSI, SPECIAL); // /< GPIO13
68
- /*
69
- for(uint8_t i = 0; i < (spiClockDiv_count); i++) {
70
- os_printf("[%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d\t Div: %d - %d\n", i, spiClockDiv[i].regEQU, spiClockDiv[i].regPre, spiClockDiv[i].regN, spiClockDiv[i].regH, spiClockDiv[i].regL, spiClockDiv[i].divider );
71
- }
72
- */
73
45
74
46
GPMUX = 0x105 ; // note crash if SPI flash Frequency < 40MHz
75
47
SPI1C = 0 ;
76
- setFrequency (1000000 ); // /< 1Mhz
48
+ setFrequency (1000000 ); // /< 1MHz
77
49
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
78
50
SPI1U1 = (7 << SPILMOSI) | (7 << SPILMISO);
79
51
SPI1C1 = 0 ;
@@ -96,15 +68,15 @@ void SPIClass::endTransaction() {
96
68
97
69
void SPIClass::setDataMode (uint8_t dataMode) {
98
70
99
- /* *
100
- SPI_MODE0 0x00 - CPOL: 0 CPHA: 0
101
- SPI_MODE1 0x01 - CPOL: 0 CPHA: 1
102
- SPI_MODE2 0x10 - CPOL: 1 CPHA: 0
103
- SPI_MODE3 0x11 - CPOL: 1 CPHA: 1
104
- */
71
+ /* *
72
+ SPI_MODE0 0x00 - CPOL: 0 CPHA: 0
73
+ SPI_MODE1 0x01 - CPOL: 0 CPHA: 1
74
+ SPI_MODE2 0x10 - CPOL: 1 CPHA: 0
75
+ SPI_MODE3 0x11 - CPOL: 1 CPHA: 1
76
+ */
105
77
106
- bool CPOL = (dataMode& 0x10 ); // /< CPOL (Clock Polarity)
107
- bool CPHA = (dataMode& 0x01 ); // /< CPHA (Clock Phase)
78
+ bool CPOL = (dataMode & 0x10 ); // /< CPOL (Clock Polarity)
79
+ bool CPHA = (dataMode & 0x01 ); // /< CPHA (Clock Phase)
108
80
109
81
if (CPHA) {
110
82
SPI1U |= (SPIUSME);
@@ -126,28 +98,105 @@ void SPIClass::setBitOrder(uint8_t bitOrder) {
126
98
}
127
99
}
128
100
101
+ /* *
102
+ * calculate the Frequency based on the register value
103
+ * @param reg
104
+ * @return
105
+ */
106
+ static uint32_t ClkRegToFreq (spiClk_t * reg) {
107
+ return (F_CPU / ((reg->regPre + 1 ) * (reg->regN + 1 )));
108
+ }
109
+
129
110
void SPIClass::setFrequency (uint32_t freq) {
130
- uint8_t i = 0 ;
111
+ static uint32_t lastSetFrequency = 0 ;
112
+ static uint32_t lastSetRegister = 0 ;
113
+
114
+ if (freq >= F_CPU) {
115
+ setClockDivider (0x80000000 );
116
+ return ;
117
+ }
118
+
119
+ if (lastSetFrequency == freq && lastSetRegister == SPI1CLK) {
120
+ // do nothing (speed optimization)
121
+ return ;
122
+ }
123
+
124
+ const spiClk_t minFreqReg = { 0x7FFFF000 };
125
+ uint32_t minFreq = ClkRegToFreq ((spiClk_t*) &minFreqReg);
126
+ if (freq < minFreq) {
127
+ freq = minFreq;
128
+ }
129
+
130
+ uint8_t calN = 1 ;
131
+
132
+ spiClk_t bestReg = { 0 };
133
+ int32_t bestFreq = 0 ;
134
+
131
135
// find the best match
132
- if (freq < F_CPU) {
133
- for (i = 1 ; i < (spiClockDiv_count-1 ); i++) {
134
- if (freq >= (F_CPU/spiClockDiv[i].divider )) {
136
+ while (calN <= 0x3F ) { // 0x3F max for N
137
+
138
+ spiClk_t reg = { 0 };
139
+ int32_t calFreq;
140
+ int32_t calPre;
141
+ int8_t calPreVari = -2 ;
142
+
143
+ reg.regN = calN;
144
+
145
+ while (calPreVari++ <= 1 ) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way)
146
+ calPre = (((F_CPU / (reg.regN + 1 )) / freq) - 1 ) + calPreVari;
147
+ if (calPre > 0x1FFF ) {
148
+ reg.regPre = 0x1FFF ; // 8191
149
+ } else if (calPre <= 0 ) {
150
+ reg.regPre = 0 ;
151
+ } else {
152
+ reg.regPre = calPre;
153
+ }
154
+
155
+ reg.regL = ((reg.regN + 1 ) / 2 );
156
+ // reg.regH = (reg.regN - reg.regL);
157
+
158
+ // test calculation
159
+ calFreq = ClkRegToFreq (®);
160
+ // os_printf("-----[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d = %d\n", reg.regValue, freq, reg.regEQU, reg.regPre, reg.regN, reg.regH, reg.regL, calFreq);
161
+
162
+ if (calFreq == (int32_t ) freq) {
163
+ // accurate match use it!
164
+ memcpy (&bestReg, ®, sizeof (bestReg));
135
165
break ;
166
+ } else if (calFreq < (int32_t ) freq) {
167
+ // never go over the requested frequency
168
+ if (abs (freq - calFreq) < abs (freq - bestFreq)) {
169
+ bestFreq = calFreq;
170
+ memcpy (&bestReg, ®, sizeof (bestReg));
171
+ }
136
172
}
137
173
}
174
+ if (calFreq == (int32_t ) freq) {
175
+ // accurate match use it!
176
+ break ;
177
+ }
178
+ calN++;
138
179
}
139
- setClockDivider (spiClockDiv[i].regValue );
180
+
181
+ // os_printf("[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d\t - Real Frequency: %d\n", bestReg.regValue, freq, bestReg.regEQU, bestReg.regPre, bestReg.regN, bestReg.regH, bestReg.regL, ClkRegToFreq(&bestReg));
182
+
183
+ setClockDivider (bestReg.regValue );
184
+ lastSetRegister = SPI1CLK;
185
+ lastSetFrequency = freq;
186
+
140
187
}
141
188
142
189
void SPIClass::setClockDivider (uint32_t clockDiv) {
143
190
SPI1CLK = clockDiv;
144
191
}
145
192
146
193
uint8_t SPIClass::transfer (uint8_t data) {
147
- while (SPI1CMD & SPIBUSY);
194
+ while (SPI1CMD & SPIBUSY)
195
+ ;
148
196
SPI1W0 = data;
149
197
SPI1CMD |= SPIBUSY;
150
- while (SPI1CMD & SPIBUSY);
198
+ while (SPI1CMD & SPIBUSY)
199
+ ;
151
200
return (uint8_t ) (SPI1W0 & 0xff );
152
201
}
153
202
0 commit comments