SmartOS之(C++)------串行外设接口类Spi

 

 

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 }

 


End!
欢迎大家一起交流 ,分享程序员励志故事。   幸福的程序员 QQ群:幸福的程序员 智能硬件群
中国嵌入式物联网群

你可能感兴趣的:(C++)