SmartOS (C++)的SPI驱动,兼容STM32F0/F1/F4/GD32F10x/GD32F1x0
头文件
1 #ifndef __SPI_H__ 2 #define __SPI_H__ 3 4 #include "Sys.h" 5 #include "Port.h" 6 7 // Spi类 8 class Spi 9 { 10 private: 11 byte _index; 12 Pin Pins[4]; // NSS/CLK/MISO/MOSI 13 OutputPort _nss; 14 15 AlternatePort _clk; 16 AlternatePort _miso; 17 AlternatePort _mosi; 18 19 void Init(); 20 21 public: 22 SPI_TypeDef* SPI; 23 int Speed; // 速度 24 int Retry; // 等待重试次数,默认200 25 int Error; // 错误次数 26 bool Opened; 27 28 Spi(); 29 // 使用端口和最大速度初始化Spi,因为需要分频,实际速度小于等于该速度 30 Spi(SPI_TypeDef* spi, uint speedHz = 9000000, bool useNss = true); 31 ~Spi(); 32 33 void Init(SPI_TypeDef* spi, uint speedHz = 9000000, bool useNss = true); 34 35 void SetPin(Pin clk = P0, Pin miso = P0, Pin mosi = P0, Pin nss = P0); 36 void GetPin(Pin* clk = NULL, Pin* miso = NULL, Pin* mosi = NULL, Pin* nss = NULL); 37 void Open(); 38 void Close(); 39 40 byte Write(byte data); 41 ushort Write16(ushort data); 42 43 void Start(); // 拉低NSS,开始传输 44 void Stop(); // 拉高NSS,停止传输 45 }; 46 47 // Spi会话类。初始化时打开Spi,超出作用域析构时关闭 48 class SpiScope 49 { 50 private: 51 Spi* _spi; 52 53 public: 54 _force_inline SpiScope(Spi* spi) 55 { 56 _spi = spi; 57 _spi->Start(); 58 } 59 60 _force_inline ~SpiScope() 61 { 62 _spi->Stop(); 63 } 64 }; 65 66 #endif 67 源码实现 68 69 #include "Sys.h" 70 #include "Port.h" 71 #include "Spi.h" 72 73 int GetPre(int index, uint* speedHz) 74 { 75 // 自动计算稍低于速度speedHz的分频 76 ushort pre = SPI_BaudRatePrescaler_2; 77 uint clock = Sys.Clock >> 1; 78 while(pre <= SPI_BaudRatePrescaler_256) 79 { 80 if(clock <= *speedHz) break; 81 clock >>= 1; 82 pre += (SPI_BaudRatePrescaler_4 - SPI_BaudRatePrescaler_2); 83 } 84 if(pre > SPI_BaudRatePrescaler_256) 85 { 86 debug_printf("Spi%d::Init Error! speedHz=%d mush be dived with %d\r\n", index, *speedHz, Sys.Clock); 87 return -1; 88 } 89 90 *speedHz = clock; 91 return pre; 92 } 93 94 Spi::Spi() 95 { 96 Init(); 97 } 98 99 Spi::Spi(SPI_TypeDef* spi, uint speedHz, bool useNss) 100 { 101 Init(); 102 103 Init(spi, speedHz, useNss); 104 } 105 106 Spi::~Spi() 107 { 108 debug_printf("Spi::~Spi%d\r\n", _index + 1); 109 110 Close(); 111 } 112 113 void Spi::Init() 114 { 115 _index = 0xFF; 116 Retry = 200; 117 Opened = false; 118 } 119 120 void Spi::Init(SPI_TypeDef* spi, uint speedHz, bool useNss) 121 { 122 assert_param(spi); 123 124 SPI_TypeDef* g_Spis[] = SPIS; 125 _index = 0xFF; 126 for(int i=0; i<ArrayLength(g_Spis); i++) 127 { 128 if(g_Spis[i] == spi) 129 { 130 _index = i; 131 break; 132 } 133 } 134 assert_param(_index < ArrayLength(g_Spis)); 135 136 SPI = g_Spis[_index]; 137 138 Pin g_Spi_Pins_Map[][4] = SPI_PINS_FULLREMAP; 139 Pin* ps = g_Spi_Pins_Map[_index]; //选定spi引脚 140 memcpy(Pins, ps, sizeof(Pins)); 141 142 if(!useNss) Pins[0] = P0; 143 144 #if DEBUG 145 int k = speedHz/1000; 146 int m = k/1000; 147 k -= m * 1000; 148 if(k == 0) 149 debug_printf("Spi%d::Init %dMHz Nss:%d\r\n", _index + 1, m, useNss); 150 else 151 debug_printf("Spi%d::Init %d.%dMHz Nss:%d\r\n", _index + 1, m, k, useNss); 152 #endif 153 154 // 自动计算稍低于速度speedHz的分频 155 int pre = GetPre(_index, &speedHz); 156 if(pre == -1) return; 157 158 Speed = speedHz; 159 } 160 161 void Spi::SetPin(Pin clk, Pin miso, Pin mosi, Pin nss) 162 { 163 if(nss != P0) Pins[0] = nss; 164 if(clk != P0) Pins[1] = clk; 165 if(miso != P0) Pins[2] = miso; 166 if(mosi != P0) Pins[3] = mosi; 167 } 168 169 void Spi::GetPin(Pin* clk, Pin* miso, Pin* mosi, Pin* nss) 170 { 171 if(nss) *nss = Pins[0]; 172 if(clk) *clk = Pins[1]; 173 if(miso) *miso = Pins[2]; 174 if(mosi) *mosi = Pins[3]; 175 } 176 177 void Spi::Open() 178 { 179 if(Opened) return; 180 181 #if DEBUG 182 int k = Speed/1000; 183 int m = k/1000; 184 k -= m * 1000; 185 if(k == 0) 186 debug_printf("Spi%d::Open %dMHz\r\n", _index + 1, m); 187 else 188 debug_printf("Spi%d::Open %d.%dMHz\r\n", _index + 1, m, k); 189 #endif 190 191 // 自动计算稍低于速度speedHz的分频 192 uint speedHz = Speed; 193 int pre = GetPre(_index, &speedHz); 194 if(pre == -1) return; 195 196 Pin* ps = Pins; 197 // 端口配置,销毁Spi对象时才释放 198 debug_printf(" CLK : "); 199 _clk.Set(ps[1]); 200 debug_printf(" MISO: "); 201 _miso.Set(ps[2]); 202 debug_printf(" MOSI: "); 203 _mosi.Set(ps[3]); 204 205 if(ps[0] != P0) 206 { 207 debug_printf(" NSS : "); 208 _nss.OpenDrain = false; 209 _nss.Set(ps[0]); 210 } 211 212 // 使能SPI时钟 213 switch(_index) 214 { 215 case 0: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); break; 216 #if defined(STM32F1) || defined(STM32F4) 217 case 1: RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); break; 218 case 2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); break; 219 #if defined(STM32F4) 220 case 3: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI4, ENABLE); break; 221 case 4: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI5, ENABLE); break; 222 case 5: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI6, ENABLE); break; 223 #endif 224 #endif 225 } 226 227 #if defined(STM32F0) 228 // SPI都在GPIO_AF_0分组内 229 GPIO_PinAFConfig(_GROUP(ps[1]), _PIN(ps[1]), GPIO_AF_0); 230 GPIO_PinAFConfig(_GROUP(ps[2]), _PIN(ps[2]), GPIO_AF_0); 231 GPIO_PinAFConfig(_GROUP(ps[3]), _PIN(ps[3]), GPIO_AF_0); 232 #elif defined(STM32F4) 233 byte afs[] = { GPIO_AF_SPI1, GPIO_AF_SPI2, GPIO_AF_SPI3, GPIO_AF_SPI4, GPIO_AF_SPI5, GPIO_AF_SPI6 }; 234 GPIO_PinAFConfig(_GROUP(ps[1]), _PIN(ps[1]), afs[_index]); 235 GPIO_PinAFConfig(_GROUP(ps[2]), _PIN(ps[2]), afs[_index]); 236 GPIO_PinAFConfig(_GROUP(ps[3]), _PIN(ps[3]), afs[_index]); 237 #endif 238 239 Stop(); 240 SPI_I2S_DeInit(SPI); 241 //SPI_DeInit(SPI); // SPI_I2S_DeInit的宏定义别名 242 243 SPI_InitTypeDef sp; 244 SPI_StructInit(&sp); 245 sp.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工 246 sp.SPI_Mode = SPI_Mode_Master; // 主模式 247 sp.SPI_DataSize = SPI_DataSize_8b; // 数据大小8位 SPI发送接收8位帧结构 248 sp.SPI_CPOL = SPI_CPOL_Low; // 时钟极性,空闲时为低 249 sp.SPI_CPHA = SPI_CPHA_1Edge; // 第1个边沿有效,上升沿为采样时刻 250 sp.SPI_NSS = SPI_NSS_Soft; // NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制 251 sp.SPI_BaudRatePrescaler = pre; // 8分频,9MHz 定义波特率预分频的值 252 sp.SPI_FirstBit = SPI_FirstBit_MSB; // 高位在前。指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 253 sp.SPI_CRCPolynomial = 7; // CRC值计算的多项式 254 255 SPI_Init(SPI, &sp); 256 SPI_Cmd(SPI, ENABLE); 257 258 Stop(); 259 260 Opened = true; 261 } 262 263 void Spi::Close() 264 { 265 if(!Opened) return; 266 267 Stop(); 268 269 SPI_Cmd(SPI, DISABLE); 270 SPI_I2S_DeInit(SPI); 271 272 debug_printf(" CLK : "); 273 _clk.Set(P0); 274 debug_printf(" MISO: "); 275 _miso.Set(P0); 276 debug_printf(" MOSI: "); 277 _mosi.Set(P0); 278 debug_printf(" NSS : "); 279 _nss.Set(P0); 280 281 Opened = false; 282 } 283 284 byte Spi::Write(byte data) 285 { 286 if(!Opened) Open(); 287 288 int retry = Retry; 289 while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET) 290 { 291 if(--retry <= 0) return ++Error; // 超时处理 292 } 293 294 #ifndef STM32F0 295 SPI_I2S_SendData(SPI, data); 296 #else 297 SPI_SendData8(SPI, data); 298 #endif 299 300 retry = Retry; 301 while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET) //是否发送成功 302 { 303 if(--retry <= 0) return ++Error; // 超时处理 304 } 305 #ifndef STM32F0 306 return SPI_I2S_ReceiveData(SPI); 307 #else 308 return SPI_ReceiveData8(SPI); //返回通过SPIx最近接收的数据 309 #endif 310 } 311 312 ushort Spi::Write16(ushort data) 313 { 314 if(!Opened) Open(); 315 316 // 双字节操作,超时次数加倍 317 int retry = Retry << 1; 318 while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_TXE) == RESET) 319 { 320 if(--retry <= 0) return ++Error; // 超时处理 321 } 322 323 #ifndef STM32F0 324 SPI_I2S_SendData(SPI, data); 325 #else 326 SPI_I2S_SendData16(SPI, data); 327 #endif 328 329 retry = Retry << 1; 330 while (SPI_I2S_GetFlagStatus(SPI, SPI_I2S_FLAG_RXNE) == RESET) 331 { 332 if(--retry <= 0) return ++Error; // 超时处理 333 } 334 335 #ifndef STM32F0 336 return SPI_I2S_ReceiveData(SPI); 337 #else 338 return SPI_I2S_ReceiveData16(SPI); 339 #endif 340 } 341 342 // 拉低NSS,开始传输 343 void Spi::Start() 344 { 345 if(!_nss.Empty()) _nss = false; 346 347 // 开始新一轮事务操作,错误次数清零 348 Error = 0; 349 } 350 351 // 拉高NSS,停止传输 352 void Spi::Stop() 353 { 354 if(!_nss.Empty()) _nss = true; 355 }