码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-01-13 08:56:49      阅读:332      评论:0      收藏:0      [点我收藏+]

标签:

 

 

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群:技术分享 智能硬件群
技术分享

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

标签:

原文地址:http://www.cnblogs.com/1hua1ye/p/4220366.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!