source: rtos_arduino/trunk/arduino_lib/hardware/arduino/samd/cores/arduino/SERCOM.cpp@ 136

Last change on this file since 136 was 136, checked in by ertl-honda, 8 years ago

ライブラリとOS及びベーシックなサンプルの追加.

File size: 13.2 KB
Line 
1#include "SERCOM.h"
2#include "variant.h"
3
4SERCOM::SERCOM(Sercom* s)
5{
6 sercom = s;
7}
8
9/* =========================
10 * ===== Sercom UART
11 * =========================
12*/
13void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate)
14{
15 resetUART();
16 initClockNVIC();
17
18 //Setting the CTRLA register
19 sercom->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(mode) |
20 SERCOM_USART_CTRLA_SAMPR(sampleRate);
21
22 //Setting the Interrupt register
23 sercom->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | //Received complete
24 SERCOM_USART_INTENSET_ERROR; //All others errors
25
26 if ( mode == UART_INT_CLOCK )
27 {
28 uint16_t sampleRateValue ;
29
30 if ( sampleRate == SAMPLE_RATE_x16 )
31 {
32 sampleRateValue = 16 ;
33 }
34 else
35 {
36 if ( sampleRate == SAMPLE_RATE_x8 )
37 {
38 sampleRateValue = 8 ;
39 }
40 else
41 {
42 sampleRateValue = 3 ;
43 }
44 }
45
46 // Asynchronous arithmetic mode
47 // 65535 * ( 1 - sampleRateValue * baudrate / SystemCoreClock);
48 // 65535 - 65535 * (sampleRateValue * baudrate / SystemCoreClock));
49 sercom->USART.BAUD.reg = 65535.0f * ( 1.0f - (float)(sampleRateValue) * (float)(baudrate) / (float)(SystemCoreClock));
50 }
51}
52void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
53{
54 //Setting the CTRLA register
55 sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_FORM( (parityMode == SERCOM_NO_PARITY ? 0 : 1) ) |
56 dataOrder << SERCOM_USART_CTRLA_DORD_Pos;
57
58 //Setting the CTRLB register
59 sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_CHSIZE(charSize) |
60 nbStopBits << SERCOM_USART_CTRLB_SBMODE_Pos |
61 (parityMode == SERCOM_NO_PARITY ? 0 : parityMode) << SERCOM_USART_CTRLB_PMODE_Pos; //If no parity use default value
62}
63
64void SERCOM::initPads(SercomUartTXPad txPad, SercomRXPad rxPad)
65{
66 //Setting the CTRLA register
67 sercom->USART.CTRLA.reg |= SERCOM_USART_CTRLA_TXPO(txPad) |
68 SERCOM_USART_CTRLA_RXPO(rxPad);
69
70 // Enable Transceiver and Receiver
71 sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
72}
73
74void SERCOM::resetUART()
75{
76 // Start the Software Reset
77 sercom->USART.CTRLA.bit.SWRST = 1 ;
78
79 while ( sercom->USART.CTRLA.bit.SWRST || sercom->USART.SYNCBUSY.bit.SWRST )
80 {
81 // Wait for both bits Software Reset from CTRLA and SYNCBUSY coming back to 0
82 }
83}
84
85void SERCOM::enableUART()
86{
87 //Setting the enable bit to 1
88 sercom->USART.CTRLA.bit.ENABLE = 0x1u;
89
90 //Wait for then enable bit from SYNCBUSY is equal to 0;
91 while(sercom->USART.SYNCBUSY.bit.ENABLE);
92}
93
94void SERCOM::flushUART()
95{
96 // Wait for transmission to complete
97 while(sercom->USART.INTFLAG.bit.DRE != SERCOM_USART_INTFLAG_DRE);
98}
99
100void SERCOM::clearStatusUART()
101{
102 //Reset (with 0) the STATUS register
103 sercom->USART.STATUS.reg = SERCOM_USART_STATUS_RESETVALUE;
104}
105
106bool SERCOM::availableDataUART()
107{
108 //RXC : Receive Complete
109 return sercom->USART.INTFLAG.bit.RXC;
110}
111
112bool SERCOM::isBufferOverflowErrorUART()
113{
114 //BUFOVF : Buffer Overflow
115 return sercom->USART.STATUS.bit.BUFOVF;
116}
117
118bool SERCOM::isFrameErrorUART()
119{
120 //FERR : Frame Error
121 return sercom->USART.STATUS.bit.FERR;
122}
123
124bool SERCOM::isParityErrorUART()
125{
126 //PERR : Parity Error
127 return sercom->USART.STATUS.bit.PERR;
128}
129
130bool SERCOM::isDataRegisterEmptyUART()
131{
132 //DRE : Data Register Empty
133 return sercom->USART.INTFLAG.bit.DRE;
134}
135
136uint8_t SERCOM::readDataUART()
137{
138 return sercom->USART.DATA.bit.DATA;
139}
140
141int SERCOM::writeDataUART(uint8_t data)
142{
143 //Flush UART buffer
144 flushUART();
145
146 //Put data into DATA register
147 sercom->USART.DATA.reg = (uint16_t)data;
148 return 1;
149}
150
151/* =========================
152 * ===== Sercom SPI
153 * =========================
154*/
155void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder)
156{
157 resetSPI();
158 initClockNVIC();
159
160 //Setting the CTRLA register
161 sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER |
162 SERCOM_SPI_CTRLA_DOPO(mosi) |
163 SERCOM_SPI_CTRLA_DIPO(miso) |
164 dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
165
166 //Setting the CTRLB register
167 sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) |
168 SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
169
170
171}
172
173void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
174{
175 //Extract data from clockMode
176 int cpha, cpol;
177
178 if((clockMode & (0x1ul)) == 0 )
179 cpha = 0;
180 else
181 cpha = 1;
182
183 if((clockMode & (0x2ul)) == 0)
184 cpol = 0;
185 else
186 cpol = 1;
187
188 //Setting the CTRLA register
189 sercom->SPI.CTRLA.reg |= ( cpha << SERCOM_SPI_CTRLA_CPHA_Pos ) |
190 ( cpol << SERCOM_SPI_CTRLA_CPOL_Pos );
191
192 //Synchronous arithmetic
193 sercom->SPI.BAUD.reg = calculateBaudrateSynchronous(baudrate);
194}
195
196void SERCOM::resetSPI()
197{
198 //Setting the Software Reset bit to 1
199 sercom->SPI.CTRLA.bit.SWRST = 1;
200
201 //Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
202 while(sercom->SPI.CTRLA.bit.SWRST || sercom->SPI.SYNCBUSY.bit.SWRST);
203}
204
205void SERCOM::enableSPI()
206{
207 //Setting the enable bit to 1
208 sercom->SPI.CTRLA.bit.ENABLE = 1;
209
210 while(sercom->SPI.SYNCBUSY.bit.ENABLE)
211 {
212 //Waiting then enable bit from SYNCBUSY is equal to 0;
213 }
214}
215
216void SERCOM::disableSPI()
217{
218 //Setting the enable bit to 0
219 sercom->SPI.CTRLA.bit.ENABLE = 0;
220
221 while(sercom->SPI.SYNCBUSY.bit.ENABLE)
222 {
223 //Waiting then enable bit from SYNCBUSY is equal to 0;
224 }
225}
226
227void SERCOM::setDataOrderSPI(SercomDataOrder dataOrder)
228{
229 //Register enable-protected
230 disableSPI();
231
232 sercom->SPI.CTRLA.bit.DORD = dataOrder;
233
234 enableSPI();
235}
236
237void SERCOM::setBaudrateSPI(uint8_t divider)
238{
239 //Can't divide by 0
240 if(divider == 0)
241 return;
242
243 //Register enable-protected
244 disableSPI();
245
246 sercom->SPI.BAUD.reg = calculateBaudrateSynchronous( SERCOM_FREQ_REF / divider );
247
248 enableSPI();
249}
250
251void SERCOM::setClockModeSPI(SercomSpiClockMode clockMode)
252{
253 int cpha, cpol;
254 if((clockMode & (0x1ul)) == 0)
255 cpha = 0;
256 else
257 cpha = 1;
258
259 if((clockMode & (0x2ul)) == 0)
260 cpol = 0;
261 else
262 cpol = 1;
263
264 //Register enable-protected
265 disableSPI();
266
267 sercom->SPI.CTRLA.bit.CPOL = cpol;
268 sercom->SPI.CTRLA.bit.CPHA = cpha;
269
270 enableSPI();
271}
272void SERCOM::writeDataSPI(uint8_t data)
273{
274 while( sercom->SPI.INTFLAG.bit.DRE == 0 )
275 {
276 // Waiting Data Registry Empty
277 }
278
279 sercom->SPI.DATA.bit.DATA = data; // Writing data into Data register
280
281 while( sercom->SPI.INTFLAG.bit.TXC == 0 || sercom->SPI.INTFLAG.bit.DRE == 0 )
282 {
283 // Waiting Complete Transmission
284 }
285}
286
287uint16_t SERCOM::readDataSPI()
288{
289 while( sercom->SPI.INTFLAG.bit.DRE == 0 || sercom->SPI.INTFLAG.bit.RXC == 0 )
290 {
291 // Waiting Complete Reception
292 }
293
294 return sercom->SPI.DATA.bit.DATA; // Reading data
295}
296
297bool SERCOM::isBufferOverflowErrorSPI()
298{
299 return sercom->SPI.STATUS.bit.BUFOVF;
300}
301
302bool SERCOM::isDataRegisterEmptySPI()
303{
304 //DRE : Data Register Empty
305 return sercom->SPI.INTFLAG.bit.DRE;
306}
307
308uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
309{
310 return SERCOM_FREQ_REF / (2 * baudrate) - 1;
311}
312
313
314/* =========================
315 * ===== Sercom WIRE
316 * =========================
317*/
318
319void SERCOM::resetWIRE()
320{
321 //I2CM OR I2CS, no matter SWRST is the same bit.
322
323 //Setting the Software bit to 1
324 sercom->I2CM.CTRLA.bit.SWRST = 1;
325
326 //Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0
327 while(sercom->I2CM.CTRLA.bit.SWRST || sercom->I2CM.SYNCBUSY.bit.SWRST);
328}
329
330void SERCOM::enableWIRE()
331{
332 // I2C Master and Slave modes share the ENABLE bit function.
333
334 // Enable the I²C master mode
335 sercom->I2CM.CTRLA.bit.ENABLE = 1 ;
336
337 while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 )
338 {
339 // Waiting the enable bit from SYNCBUSY is equal to 0;
340 }
341
342 // Setting bus idle mode
343 sercom->I2CM.STATUS.bit.BUSSTATE = 1 ;
344
345 while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 )
346 {
347 // Wait the SYSOP bit from SYNCBUSY coming back to 0
348 }
349}
350
351void SERCOM::disableWIRE()
352{
353 // I2C Master and Slave modes share the ENABLE bit function.
354
355 // Enable the I²C master mode
356 sercom->I2CM.CTRLA.bit.ENABLE = 0 ;
357
358 while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 )
359 {
360 // Waiting the enable bit from SYNCBUSY is equal to 0;
361 }
362}
363
364void SERCOM::initSlaveWIRE( uint8_t ucAddress )
365{
366 // Initialize the peripheral clock and interruption
367 initClockNVIC() ;
368 resetWIRE() ;
369
370 // Set slave mode
371 sercom->I2CS.CTRLA.bit.MODE = I2C_SLAVE_OPERATION ;
372
373 // Enable Quick Command
374 sercom->I2CM.CTRLB.bit.QCEN = 1 ;
375
376 sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits
377 SERCOM_I2CS_ADDR_ADDRMASK( 0x3FFul ) ; // 0x3FF all bits set
378
379 // Set the interrupt register
380 sercom->I2CS.INTENSET.reg = SERCOM_I2CS_INTENSET_AMATCH | // Address Match
381 SERCOM_I2CS_INTENSET_DRDY ; // Data Ready
382
383 while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 )
384 {
385 // Wait the SYSOP bit from SYNCBUSY to come back to 0
386 }
387}
388
389void SERCOM::initMasterWIRE( uint32_t baudrate )
390{
391 // Initialize the peripheral clock and interruption
392 initClockNVIC() ;
393
394 resetWIRE() ;
395
396 // Set master mode and enable SCL Clock Stretch mode (stretch after ACK bit)
397 sercom->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION );
398
399 // Enable Smart mode and Quick Command
400
401 // Enable all interrupts
402
403 // Synchronous arithmetic baudrate
404 sercom->I2CM.BAUD.bit.BAUD = SystemCoreClock / ( 2 * baudrate) - 1 ;
405}
406
407void SERCOM::prepareNackBitWIRE( void )
408{
409 // Send a NACK
410 sercom->I2CM.CTRLB.bit.ACKACT = 1;
411}
412
413void SERCOM::prepareAckBitWIRE( void )
414{
415 // Send an ACK
416 sercom->I2CM.CTRLB.bit.ACKACT = 0;
417}
418
419void SERCOM::prepareCommandBitsWire(SercomMasterCommandWire cmd)
420{
421 sercom->I2CM.CTRLB.bit.CMD = cmd;
422
423 while(sercom->I2CM.SYNCBUSY.bit.SYSOP)
424 {
425 // Waiting for synchronization
426 }
427}
428
429bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag)
430{
431 // 7-bits address + 1-bits R/W
432 address = (address << 0x1ul) | flag;
433
434 // Wait idle bus mode
435 while ( !isBusIdleWIRE() );
436
437 // Send start and address
438 sercom->I2CM.ADDR.bit.ADDR = address;
439
440 // Address Transmitted
441 if ( flag == WIRE_WRITE_FLAG ) // Write mode
442 {
443 while( !sercom->I2CM.INTFLAG.bit.MB )
444 {
445 // Wait transmission complete
446 }
447 }
448 else // Read mode
449 {
450 while( !sercom->I2CM.INTFLAG.bit.SB )
451 {
452 // Wait transmission complete
453 }
454
455 // Clean the 'Slave on Bus' flag, for further usage.
456 //sercom->I2CM.INTFLAG.bit.SB = 0x1ul;
457 }
458
459
460 //ACK received (0: ACK, 1: NACK)
461 if(sercom->I2CM.STATUS.bit.RXNACK)
462 {
463 return false;
464 }
465 else
466 {
467 return true;
468 }
469}
470
471bool SERCOM::sendDataMasterWIRE(uint8_t data)
472{
473 //Send data
474 sercom->I2CM.DATA.bit.DATA = data;
475
476 //Wait transmission successful
477 while(!sercom->I2CM.INTFLAG.bit.MB);
478
479 //Problems on line? nack received?
480 if(sercom->I2CM.STATUS.bit.RXNACK)
481 return false;
482 else
483 return true;
484}
485
486bool SERCOM::sendDataSlaveWIRE(uint8_t data)
487{
488 //Send data
489 sercom->I2CS.DATA.bit.DATA = data;
490
491 //Wait data transmission successful
492 while(!sercom->I2CS.INTFLAG.bit.DRDY);
493
494 //Problems on line? nack received?
495 if(sercom->I2CS.STATUS.bit.RXNACK)
496 return false;
497 else
498 return true;
499}
500
501bool SERCOM::isMasterWIRE( void )
502{
503 return sercom->I2CS.CTRLA.bit.MODE == I2C_MASTER_OPERATION;
504}
505
506bool SERCOM::isSlaveWIRE( void )
507{
508 return sercom->I2CS.CTRLA.bit.MODE == I2C_SLAVE_OPERATION;
509}
510
511bool SERCOM::isBusIdleWIRE( void )
512{
513 return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_IDLE_STATE;
514}
515
516bool SERCOM::isDataReadyWIRE( void )
517{
518 return sercom->I2CS.INTFLAG.bit.DRDY;
519}
520
521bool SERCOM::isStopDetectedWIRE( void )
522{
523 return sercom->I2CS.INTFLAG.bit.PREC;
524}
525
526bool SERCOM::isRestartDetectedWIRE( void )
527{
528 return sercom->I2CS.STATUS.bit.SR;
529}
530
531bool SERCOM::isAddressMatch( void )
532{
533 return sercom->I2CS.INTFLAG.bit.AMATCH;
534}
535
536bool SERCOM::isMasterReadOperationWIRE( void )
537{
538 return sercom->I2CS.STATUS.bit.DIR;
539}
540
541bool SERCOM::isRXNackReceivedWIRE( void )
542{
543 return sercom->I2CM.STATUS.bit.RXNACK;
544}
545
546int SERCOM::availableWIRE( void )
547{
548 if(isMasterWIRE())
549 return sercom->I2CM.INTFLAG.bit.SB;
550 else
551 return sercom->I2CS.INTFLAG.bit.DRDY;
552}
553
554uint8_t SERCOM::readDataWIRE( void )
555{
556 if(isMasterWIRE())
557 {
558 while( sercom->I2CM.INTFLAG.bit.SB == 0 )
559 {
560 // Waiting complete receive
561 }
562
563 return sercom->I2CM.DATA.bit.DATA ;
564 }
565 else
566 {
567 return sercom->I2CS.DATA.reg ;
568 }
569}
570
571
572void SERCOM::initClockNVIC( void )
573{
574 uint8_t clockId = 0;
575 IRQn_Type IdNvic;
576
577 if(sercom == SERCOM0)
578 {
579 clockId = GCM_SERCOM0_CORE;
580 IdNvic = SERCOM0_IRQn;
581 }
582 else if(sercom == SERCOM1)
583 {
584 clockId = GCM_SERCOM1_CORE;
585 IdNvic = SERCOM1_IRQn;
586 }
587 else if(sercom == SERCOM2)
588 {
589 clockId = GCM_SERCOM2_CORE;
590 IdNvic = SERCOM2_IRQn;
591 }
592 else if(sercom == SERCOM3)
593 {
594 clockId = GCM_SERCOM3_CORE;
595 IdNvic = SERCOM3_IRQn;
596 }
597 else if(sercom == SERCOM4)
598 {
599 clockId = GCM_SERCOM4_CORE;
600 IdNvic = SERCOM4_IRQn;
601 }
602 else if(sercom == SERCOM5)
603 {
604 clockId = GCM_SERCOM5_CORE;
605 IdNvic = SERCOM5_IRQn;
606 }
607
608 // Setting NVIC
609 NVIC_EnableIRQ(IdNvic);
610 NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */
611
612 //Setting clock
613 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
614 GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
615 GCLK_CLKCTRL_CLKEN ;
616
617 while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
618 {
619 /* Wait for synchronization */
620 }
621
622}
Note: See TracBrowser for help on using the repository browser.