@@ -305,7 +305,11 @@ void SERCOM::setBaudrateSPI(uint8_t divider)
305
305
{
306
306
disableSPI (); // Register is enable-protected
307
307
308
+ #if defined(__SAMD51__)
309
+ sercom->SPI .BAUD .reg = calculateBaudrateSynchronous (freqRef / divider);
310
+ #else
308
311
sercom->SPI .BAUD .reg = calculateBaudrateSynchronous (SERCOM_SPI_FREQ_REF / divider);
312
+ #endif
309
313
310
314
enableSPI ();
311
315
}
@@ -364,9 +368,12 @@ bool SERCOM::isDataRegisterEmptySPI()
364
368
// return sercom->SPI.INTFLAG.bit.RXC;
365
369
// }
366
370
367
- uint8_t SERCOM::calculateBaudrateSynchronous (uint32_t baudrate)
368
- {
371
+ uint8_t SERCOM::calculateBaudrateSynchronous (uint32_t baudrate) {
372
+ #if defined(__SAMD51__)
373
+ uint16_t b = freqRef / (2 * baudrate);
374
+ #else
369
375
uint16_t b = SERCOM_SPI_FREQ_REF / (2 * baudrate);
376
+ #endif
370
377
if (b > 0 ) b--; // Don't -1 on baud calc if already at 0
371
378
return b;
372
379
}
@@ -664,163 +671,152 @@ uint8_t SERCOM::readDataWIRE( void )
664
671
}
665
672
}
666
673
667
-
668
- void SERCOM::initClockNVIC ( void )
669
- {
670
674
#if defined(__SAMD51__)
671
- uint32_t clk_core, clk_slow;
672
- IRQn_Type irq0, irq1, irq2, irq3;
673
-
674
- if (sercom == SERCOM0) {
675
- clk_core = SERCOM0_GCLK_ID_CORE;
676
- clk_slow = SERCOM0_GCLK_ID_SLOW;
677
- irq0 = SERCOM0_0_IRQn;
678
- irq1 = SERCOM0_1_IRQn;
679
- irq2 = SERCOM0_2_IRQn;
680
- irq3 = SERCOM0_3_IRQn;
681
- } else if (sercom == SERCOM1) {
682
- clk_core = SERCOM1_GCLK_ID_CORE;
683
- clk_slow = SERCOM1_GCLK_ID_SLOW;
684
- irq0 = SERCOM1_0_IRQn;
685
- irq1 = SERCOM1_1_IRQn;
686
- irq2 = SERCOM1_2_IRQn;
687
- irq3 = SERCOM1_3_IRQn;
688
- } else if (sercom == SERCOM2) {
689
- clk_core = SERCOM2_GCLK_ID_CORE;
690
- clk_slow = SERCOM2_GCLK_ID_SLOW;
691
- irq0 = SERCOM2_0_IRQn;
692
- irq1 = SERCOM2_1_IRQn;
693
- irq2 = SERCOM2_2_IRQn;
694
- irq3 = SERCOM2_3_IRQn;
695
- } else if (sercom == SERCOM3) {
696
- clk_core = SERCOM3_GCLK_ID_CORE;
697
- clk_slow = SERCOM3_GCLK_ID_SLOW;
698
- irq0 = SERCOM3_0_IRQn;
699
- irq1 = SERCOM3_1_IRQn;
700
- irq2 = SERCOM3_2_IRQn;
701
- irq3 = SERCOM3_3_IRQn;
702
- } else if (sercom == SERCOM4) {
703
- clk_core = SERCOM4_GCLK_ID_CORE;
704
- clk_slow = SERCOM4_GCLK_ID_SLOW;
705
- irq0 = SERCOM4_0_IRQn;
706
- irq1 = SERCOM4_1_IRQn;
707
- irq2 = SERCOM4_2_IRQn;
708
- irq3 = SERCOM4_3_IRQn;
709
- } else if (sercom == SERCOM5) {
710
- clk_core = SERCOM5_GCLK_ID_CORE;
711
- clk_slow = SERCOM5_GCLK_ID_SLOW;
712
- irq0 = SERCOM5_0_IRQn;
713
- irq1 = SERCOM5_1_IRQn;
714
- irq2 = SERCOM5_2_IRQn;
715
- irq3 = SERCOM5_3_IRQn;
716
- }
717
- #if defined SERCOM6
718
- else if (sercom == SERCOM6) {
719
- clk_core = SERCOM6_GCLK_ID_CORE;
720
- clk_slow = SERCOM6_GCLK_ID_SLOW;
721
- irq0 = (SERCOM6_0_IRQn);
722
- irq1 = (SERCOM6_1_IRQn);
723
- irq2 = (SERCOM6_2_IRQn);
724
- irq3 = (SERCOM6_3_IRQn);
725
- }
726
- #endif // end SERCOM6
727
- #if defined SERCOM7
728
- else if (sercom == SERCOM7) {
729
- clk_core = SERCOM7_GCLK_ID_CORE;
730
- clk_slow = SERCOM7_GCLK_ID_SLOW;
731
- irq0 = (SERCOM7_0_IRQn);
732
- irq1 = (SERCOM7_1_IRQn);
733
- irq2 = (SERCOM7_2_IRQn);
734
- irq3 = (SERCOM7_3_IRQn);
675
+
676
+ static const struct {
677
+ Sercom *sercomPtr;
678
+ uint8_t id_core;
679
+ uint8_t id_slow;
680
+ IRQn_Type irq[4 ];
681
+ } sercomData[] = {
682
+ { SERCOM0, SERCOM0_GCLK_ID_CORE, SERCOM0_GCLK_ID_SLOW,
683
+ SERCOM0_0_IRQn, SERCOM0_1_IRQn, SERCOM0_2_IRQn, SERCOM0_3_IRQn },
684
+ { SERCOM1, SERCOM1_GCLK_ID_CORE, SERCOM1_GCLK_ID_SLOW,
685
+ SERCOM1_0_IRQn, SERCOM1_1_IRQn, SERCOM1_2_IRQn, SERCOM1_3_IRQn },
686
+ { SERCOM2, SERCOM2_GCLK_ID_CORE, SERCOM2_GCLK_ID_SLOW,
687
+ SERCOM2_0_IRQn, SERCOM2_1_IRQn, SERCOM2_2_IRQn, SERCOM2_3_IRQn },
688
+ { SERCOM3, SERCOM3_GCLK_ID_CORE, SERCOM3_GCLK_ID_SLOW,
689
+ SERCOM3_0_IRQn, SERCOM3_1_IRQn, SERCOM3_2_IRQn, SERCOM3_3_IRQn },
690
+ { SERCOM4, SERCOM4_GCLK_ID_CORE, SERCOM4_GCLK_ID_SLOW,
691
+ SERCOM4_0_IRQn, SERCOM4_1_IRQn, SERCOM4_2_IRQn, SERCOM4_3_IRQn },
692
+ { SERCOM5, SERCOM5_GCLK_ID_CORE, SERCOM5_GCLK_ID_SLOW,
693
+ SERCOM5_0_IRQn, SERCOM5_1_IRQn, SERCOM5_2_IRQn, SERCOM5_3_IRQn },
694
+ #if defined(SERCOM6)
695
+ { SERCOM6, SERCOM6_GCLK_ID_CORE, SERCOM6_GCLK_ID_SLOW,
696
+ SERCOM6_0_IRQn, SERCOM6_1_IRQn, SERCOM6_2_IRQn, SERCOM6_3_IRQn },
697
+ #endif
698
+ #if defined(SERCOM7)
699
+ { SERCOM7, SERCOM7_GCLK_ID_CORE, SERCOM7_GCLK_ID_SLOW,
700
+ SERCOM7_0_IRQn, SERCOM7_1_IRQn, SERCOM7_2_IRQn, SERCOM7_3_IRQn },
701
+ #endif
702
+ };
703
+
704
+ #else // end if SAMD51 (prob SAMD21)
705
+
706
+ static const struct {
707
+ Sercom *sercomPtr;
708
+ uint8_t clock;
709
+ IRQn_Type irqn;
710
+ } sercomData[] = {
711
+ SERCOM0, GCM_SERCOM0_CORE, SERCOM0_IRQn,
712
+ SERCOM1, GCM_SERCOM1_CORE, SERCOM1_IRQn,
713
+ SERCOM2, GCM_SERCOM2_CORE, SERCOM2_IRQn,
714
+ SERCOM3, GCM_SERCOM3_CORE, SERCOM3_IRQn,
715
+ #if defined(SERCOM4)
716
+ SERCOM4, GCM_SERCOM4_CORE, SERCOM4_IRQn,
717
+ #endif
718
+ #if defined(SERCOM5)
719
+ SERCOM5, GCM_SERCOM5_CORE, SERCOM5_IRQn,
720
+ #endif
721
+ };
722
+
723
+ #endif // end !SAMD51
724
+
725
+ int8_t SERCOM::getSercomIndex (void ) {
726
+ for (uint8_t i=0 ; i<(sizeof (sercomData) / sizeof (sercomData[0 ])); i++) {
727
+ if (sercom == sercomData[i].sercomPtr ) return i;
735
728
}
736
- #endif // end SERCOM7
737
- NVIC_ClearPendingIRQ (irq0);
738
- NVIC_ClearPendingIRQ (irq1);
739
- NVIC_ClearPendingIRQ (irq2);
740
- NVIC_ClearPendingIRQ (irq3);
741
-
742
- NVIC_SetPriority (irq0, (1 <<__NVIC_PRIO_BITS) - 1 );
743
- NVIC_SetPriority (irq1, (1 <<__NVIC_PRIO_BITS) - 1 );
744
- NVIC_SetPriority (irq2, (1 <<__NVIC_PRIO_BITS) - 1 );
745
- NVIC_SetPriority (irq3, (1 <<__NVIC_PRIO_BITS) - 1 );
746
-
747
- NVIC_EnableIRQ (irq0);
748
- NVIC_EnableIRQ (irq1);
749
- NVIC_EnableIRQ (irq2);
750
- NVIC_EnableIRQ (irq3);
751
-
752
- GCLK->PCHCTRL [clk_core].bit .CHEN = 0 ; // Disable core timer
753
- while (GCLK->PCHCTRL [clk_core].bit .CHEN ); // Wait for disable
754
- GCLK->PCHCTRL [clk_slow].bit .CHEN = 0 ; // Disable slow timer
755
- while (GCLK->PCHCTRL [clk_slow].bit .CHEN ); // Wait for disable
729
+ return -1 ;
730
+ }
731
+
732
+ #if defined(__SAMD51__)
733
+ // This is currently for overriding an SPI SERCOM's clock source only --
734
+ // NOT for UART or WIRE SERCOMs, where it will have unintended consequences.
735
+ // It does not check.
736
+ void SERCOM::setClockSource (int idx, SercomClockSource src, bool core) {
737
+
738
+ uint8_t clk_id = core ? sercomData[idx].id_core : sercomData[idx].id_slow ;
739
+
740
+ GCLK->PCHCTRL [clk_id].bit .CHEN = 0 ; // Disable timer
741
+ while (GCLK->PCHCTRL [clk_id].bit .CHEN ); // Wait for disable
756
742
757
- // SPI DMA speed is dictated by the "slow clock," so BOTH are set to the
758
- // same clock source (clk_slow isn't sourced from XOSC32K as before).
759
- // This might have power implications for sleep code.
760
743
// From cores/arduino/startup.c:
761
744
// GCLK0 = F_CPU
762
745
// GCLK1 = 48 MHz
763
746
// GCLK2 = 100 MHz
764
747
// GCLK3 = XOSC32K
765
748
// GCLK4 = 12 MHz
766
- #if SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1
767
- GCLK->PCHCTRL [clk_core].reg = GCLK_PCHCTRL_GEN_GCLK1_Val |
768
- (1 << GCLK_PCHCTRL_CHEN_Pos);
769
- GCLK->PCHCTRL [clk_slow].reg = GCLK_PCHCTRL_GEN_GCLK1_Val |
770
- (1 << GCLK_PCHCTRL_CHEN_Pos);
749
+ if (src == SERCOM_CLOCK_SOURCE_FCPU) {
750
+ GCLK->PCHCTRL [clk_id].reg =
751
+ GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
752
+ if (core) freqRef = F_CPU;
753
+ } else if (src == SERCOM_CLOCK_SOURCE_48M) {
754
+ GCLK->PCHCTRL [clk_id].reg =
755
+ GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
756
+ if (core) freqRef = 48000000 ;
757
+ } else if (src == SERCOM_CLOCK_SOURCE_100M) {
758
+ GCLK->PCHCTRL [clk_id].reg =
759
+ GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
760
+ if (core) freqRef = 100000000 ;
761
+ } else if (src == SERCOM_CLOCK_SOURCE_32K) {
762
+ GCLK->PCHCTRL [clk_id].reg =
763
+ GCLK_PCHCTRL_GEN_GCLK3_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
764
+ if (core) freqRef = 32768 ;
765
+ } else if (src == SERCOM_CLOCK_SOURCE_12M) {
766
+ GCLK->PCHCTRL [clk_id].reg =
767
+ GCLK_PCHCTRL_GEN_GCLK4_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
768
+ if (core) freqRef = 12000000 ;
769
+ }
770
+
771
+ while (!GCLK->PCHCTRL [clk_id].bit .CHEN ); // Wait for clock enable
772
+ }
773
+ #endif
774
+
775
+ void SERCOM::initClockNVIC ( void )
776
+ {
777
+ int8_t idx = getSercomIndex ();
778
+ if (idx < 0 ) return ; // We got a problem here
779
+
780
+ #if defined(__SAMD51__)
781
+
782
+ for (uint8_t i=0 ; i<4 ; i++) {
783
+ NVIC_ClearPendingIRQ (sercomData[idx].irq [i]);
784
+ NVIC_SetPriority (sercomData[idx].irq [i], SERCOM_NVIC_PRIORITY);
785
+ NVIC_EnableIRQ (sercomData[idx].irq [i]);
786
+ }
787
+
788
+ // A briefly-availabe but now deprecated feature had the SPI clock source
789
+ // set via a compile-time setting (MAX_SPI)...problem was this affected
790
+ // ALL SERCOMs, whereas some (anything read/write, e.g. SD cards) should
791
+ // not exceed the standard 24 MHz setting. Newer code, if it needs faster
792
+ // write-only SPI (e.g. to screen), should override the SERCOM clock on a
793
+ // per-peripheral basis. Nonetheless, we check SERCOM_SPI_FREQ_REF here
794
+ // (MAX_SPI * 2) to retain compatibility with any interim projects that
795
+ // might have relied on the compile-time setting. But please, don't.
796
+
797
+ // SPI DMA speed is dictated by the "slow clock," so BOTH are set to the
798
+ // same clock source (clk_slow isn't sourced from XOSC32K as before).
799
+ // This might have power implications for sleep code.
800
+
801
+ #if SERCOM_SPI_FREQ_REF == F_CPU // F_CPU clock = GCLK0
802
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_FCPU, true ); // true = core clock
803
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_FCPU, false ); // false = slow clock
804
+ #elif SERCOM_SPI_FREQ_REF == 48000000 // 48 MHz clock = GCLK1 (standard)
805
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_48M , true );
806
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_48M , false );
771
807
#elif SERCOM_SPI_FREQ_REF == 100000000 // 100 MHz clock = GCLK2
772
- GCLK->PCHCTRL [clk_core].reg = GCLK_PCHCTRL_GEN_GCLK2_Val |
773
- (1 << GCLK_PCHCTRL_CHEN_Pos);
774
- GCLK->PCHCTRL [clk_slow].reg = GCLK_PCHCTRL_GEN_GCLK2_Val |
775
- (1 << GCLK_PCHCTRL_CHEN_Pos);
776
- #elif SERCOM_SPI_FREQ_REF == F_CPU // F_CPU clock = GCLK0
777
- GCLK->PCHCTRL [clk_core].reg = GCLK_PCHCTRL_GEN_GCLK0_Val |
778
- (1 << GCLK_PCHCTRL_CHEN_Pos);
779
- GCLK->PCHCTRL [clk_slow].reg = GCLK_PCHCTRL_GEN_GCLK0_Val |
780
- (1 << GCLK_PCHCTRL_CHEN_Pos);
808
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_100M, true );
809
+ setClockSource (idx, SERCOM_CLOCK_SOURCE_100M, false );
781
810
#endif
782
811
783
- while (!GCLK->PCHCTRL [clk_core].bit .CHEN ); // Wait for core clock enable
784
- while (!GCLK->PCHCTRL [clk_slow].bit .CHEN ); // Wait for slow clock enable
785
-
786
- #else // end if SAMD51
787
-
788
- IRQn_Type IdNvic=PendSV_IRQn ; // Dummy init to intercept potential error later
789
-
790
- uint8_t clockId = 0 ;
791
- if (sercom == SERCOM0) {
792
- clockId = GCM_SERCOM0_CORE;
793
- IdNvic = SERCOM0_IRQn;
794
- } else if (sercom == SERCOM1) {
795
- clockId = GCM_SERCOM1_CORE;
796
- IdNvic = SERCOM1_IRQn;
797
- } else if (sercom == SERCOM2) {
798
- clockId = GCM_SERCOM2_CORE;
799
- IdNvic = SERCOM2_IRQn;
800
- } else if (sercom == SERCOM3) {
801
- clockId = GCM_SERCOM3_CORE;
802
- IdNvic = SERCOM3_IRQn;
803
- }
804
- #if defined(SERCOM4)
805
- else if (sercom == SERCOM4) {
806
- clockId = GCM_SERCOM4_CORE;
807
- IdNvic = SERCOM4_IRQn;
808
- }
809
- #endif // end SERCOM4
810
- #if defined(SERCOM5)
811
- else if (sercom == SERCOM5) {
812
- clockId = GCM_SERCOM5_CORE;
813
- IdNvic = SERCOM5_IRQn;
814
- }
815
- #endif // end SERCOM5
812
+ #else // end if SAMD51 (prob SAMD21)
816
813
817
- if (IdNvic == PendSV_IRQn) {
818
- return ; // We got a problem here
819
- }
814
+ uint8_t clockId = sercomData[idx].clock ;
815
+ IRQn_Type IdNvic = sercomData[idx].irqn ;
820
816
821
- // Setting NVIC
817
+ // Setting NVIC
822
818
NVIC_ClearPendingIRQ (IdNvic);
823
- NVIC_SetPriority (IdNvic, ( 1 <<__NVIC_PRIO_BITS) - 1 );
819
+ NVIC_SetPriority (IdNvic, SERCOM_NVIC_PRIORITY );
824
820
NVIC_EnableIRQ (IdNvic);
825
821
826
822
// Setting clock
@@ -830,5 +826,6 @@ void SERCOM::initClockNVIC( void )
830
826
GCLK_CLKCTRL_CLKEN;
831
827
832
828
while (GCLK->STATUS .reg & GCLK_STATUS_SYNCBUSY); // Wait for synchronization
829
+
833
830
#endif // end !SAMD51
834
831
}
0 commit comments