same54xplainedpro.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2021 Jean Gressmann <jean@0x42.de>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. */
  25. #include <sam.h>
  26. #include "bsp/board.h"
  27. #include <hal/include/hal_gpio.h>
  28. //--------------------------------------------------------------------+
  29. // Forward USB interrupt events to TinyUSB IRQ Handler
  30. //--------------------------------------------------------------------+
  31. void USB_0_Handler(void)
  32. {
  33. tud_int_handler(0);
  34. }
  35. void USB_1_Handler(void)
  36. {
  37. tud_int_handler(0);
  38. }
  39. void USB_2_Handler(void)
  40. {
  41. tud_int_handler(0);
  42. }
  43. void USB_3_Handler(void)
  44. {
  45. tud_int_handler(0);
  46. }
  47. //--------------------------------------------------------------------+
  48. // MACRO TYPEDEF CONSTANT ENUM DECLARATION
  49. //--------------------------------------------------------------------+
  50. #define LED_PIN PIN_PC18
  51. #define BUTTON_PIN PIN_PB31
  52. #define BOARD_SERCOM SERCOM2
  53. /** Initializes the clocks from the external 12 MHz crystal
  54. *
  55. * The goal of this setup is to preserve the second PLL
  56. * for the application code while still having a reasonable
  57. * 48 MHz clock for USB / UART.
  58. *
  59. * GCLK0: CONF_CPU_FREQUENCY (default 120 MHz) from PLL0
  60. * GCLK1: unused
  61. * GCLK2: 12 MHz from XOSC1
  62. * DFLL48M: closed loop from GLCK2
  63. * GCLK3: 48 MHz
  64. */
  65. static inline void init_clock_xtal(void)
  66. {
  67. /* configure for a 12MHz crystal connected to XIN1/XOUT1 */
  68. OSCCTRL->XOSCCTRL[1].reg =
  69. OSCCTRL_XOSCCTRL_STARTUP(6) | // 1.953 ms
  70. OSCCTRL_XOSCCTRL_RUNSTDBY |
  71. OSCCTRL_XOSCCTRL_ENALC |
  72. OSCCTRL_XOSCCTRL_IMULT(4) | OSCCTRL_XOSCCTRL_IPTAT(3) | // 8MHz to 16MHz
  73. OSCCTRL_XOSCCTRL_XTALEN |
  74. OSCCTRL_XOSCCTRL_ENABLE;
  75. while(0 == OSCCTRL->STATUS.bit.XOSCRDY1);
  76. OSCCTRL->Dpll[0].DPLLCTRLB.reg = OSCCTRL_DPLLCTRLB_DIV(2) | OSCCTRL_DPLLCTRLB_REFCLK_XOSC1; /* 12MHz / 6 = 2Mhz, input = XOSC1 */
  77. OSCCTRL->Dpll[0].DPLLRATIO.reg = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR((CONF_CPU_FREQUENCY / 1000000 / 2) - 1); /* multiply to get CONF_CPU_FREQUENCY (default = 120MHz) */
  78. OSCCTRL->Dpll[0].DPLLCTRLA.reg = OSCCTRL_DPLLCTRLA_RUNSTDBY | OSCCTRL_DPLLCTRLA_ENABLE;
  79. while(0 == OSCCTRL->Dpll[0].DPLLSTATUS.bit.CLKRDY); /* wait for the PLL0 to be ready */
  80. /* configure clock-generator 0 to use DPLL0 as source -> GCLK0 is used for the core */
  81. GCLK->GENCTRL[0].reg =
  82. GCLK_GENCTRL_DIV(0) |
  83. GCLK_GENCTRL_RUNSTDBY |
  84. GCLK_GENCTRL_GENEN |
  85. GCLK_GENCTRL_SRC_DPLL0 |
  86. GCLK_GENCTRL_IDC;
  87. while(1 == GCLK->SYNCBUSY.bit.GENCTRL0); /* wait for the synchronization between clock domains to be complete */
  88. // configure GCLK2 for 12MHz from XOSC1
  89. GCLK->GENCTRL[2].reg =
  90. GCLK_GENCTRL_DIV(0) |
  91. GCLK_GENCTRL_RUNSTDBY |
  92. GCLK_GENCTRL_GENEN |
  93. GCLK_GENCTRL_SRC_XOSC1 |
  94. GCLK_GENCTRL_IDC;
  95. while(1 == GCLK->SYNCBUSY.bit.GENCTRL2); /* wait for the synchronization between clock domains to be complete */
  96. /* setup DFLL48M to use GLCK2 */
  97. GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_GEN_GCLK2 | GCLK_PCHCTRL_CHEN;
  98. OSCCTRL->DFLLCTRLA.reg = 0;
  99. while(1 == OSCCTRL->DFLLSYNC.bit.ENABLE);
  100. OSCCTRL->DFLLCTRLB.reg = OSCCTRL_DFLLCTRLB_MODE | OSCCTRL_DFLLCTRLB_WAITLOCK;
  101. OSCCTRL->DFLLMUL.bit.MUL = 4; // 4 * 12MHz -> 48MHz
  102. OSCCTRL->DFLLCTRLA.reg =
  103. OSCCTRL_DFLLCTRLA_ENABLE |
  104. OSCCTRL_DFLLCTRLA_RUNSTDBY;
  105. while(1 == OSCCTRL->DFLLSYNC.bit.ENABLE);
  106. // setup 48 MHz GCLK3 from DFLL48M
  107. GCLK->GENCTRL[3].reg =
  108. GCLK_GENCTRL_DIV(0) |
  109. GCLK_GENCTRL_RUNSTDBY |
  110. GCLK_GENCTRL_GENEN |
  111. GCLK_GENCTRL_SRC_DFLL |
  112. GCLK_GENCTRL_IDC;
  113. while(1 == GCLK->SYNCBUSY.bit.GENCTRL3);
  114. }
  115. /* Initialize SERCOM2 for 115200 bps 8N1 using a 48 MHz clock */
  116. static inline void uart_init(void)
  117. {
  118. gpio_set_pin_function(PIN_PB24, PINMUX_PB24D_SERCOM2_PAD1);
  119. gpio_set_pin_function(PIN_PB25, PINMUX_PB25D_SERCOM2_PAD0);
  120. MCLK->APBBMASK.bit.SERCOM2_ = 1;
  121. GCLK->PCHCTRL[SERCOM2_GCLK_ID_CORE].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN;
  122. BOARD_SERCOM->USART.CTRLA.bit.SWRST = 1; /* reset and disable SERCOM -> enable configuration */
  123. while (BOARD_SERCOM->USART.SYNCBUSY.bit.SWRST);
  124. BOARD_SERCOM->USART.CTRLA.reg =
  125. SERCOM_USART_CTRLA_SAMPR(0) | /* 0 = 16x / arithmetic baud rate, 1 = 16x / fractional baud rate */
  126. SERCOM_USART_CTRLA_SAMPA(0) | /* 16x over sampling */
  127. SERCOM_USART_CTRLA_FORM(0) | /* 0x0 USART frame, 0x1 USART frame with parity, ... */
  128. SERCOM_USART_CTRLA_DORD | /* LSB first */
  129. SERCOM_USART_CTRLA_MODE(1) | /* 0x0 USART with external clock, 0x1 USART with internal clock */
  130. SERCOM_USART_CTRLA_RXPO(1) | /* SERCOM PAD[1] is used for data reception */
  131. SERCOM_USART_CTRLA_TXPO(0); /* SERCOM PAD[0] is used for data transmission */
  132. BOARD_SERCOM->USART.CTRLB.reg = /* RXEM = 0 -> receiver disabled, LINCMD = 0 -> normal USART transmission, SFDE = 0 -> start-of-frame detection disabled, SBMODE = 0 -> one stop bit, CHSIZE = 0 -> 8 bits */
  133. SERCOM_USART_CTRLB_TXEN | /* transmitter enabled */
  134. SERCOM_USART_CTRLB_RXEN; /* receiver enabled */
  135. // BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_FRAC_FP(0) | SERCOM_USART_BAUD_FRAC_BAUD(26); /* 48000000/(16*115200) = 26.041666667 */
  136. BOARD_SERCOM->USART.BAUD.reg = SERCOM_USART_BAUD_BAUD(63019); /* 65536*(1−16*115200/48000000) */
  137. BOARD_SERCOM->USART.CTRLA.bit.ENABLE = 1; /* activate SERCOM */
  138. while (BOARD_SERCOM->USART.SYNCBUSY.bit.ENABLE); /* wait for SERCOM to be ready */
  139. }
  140. static inline void uart_send_buffer(uint8_t const *text, size_t len)
  141. {
  142. for (size_t i = 0; i < len; ++i) {
  143. BOARD_SERCOM->USART.DATA.reg = text[i];
  144. while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) == 0);
  145. }
  146. }
  147. static inline void uart_send_str(const char* text)
  148. {
  149. while (*text) {
  150. BOARD_SERCOM->USART.DATA.reg = *text++;
  151. while((BOARD_SERCOM->USART.INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) == 0);
  152. }
  153. }
  154. void board_init(void)
  155. {
  156. // Uncomment this line and change the GCLK for UART/USB to run off the XTAL.
  157. // init_clock_xtal();
  158. SystemCoreClock = CONF_CPU_FREQUENCY;
  159. #if CFG_TUSB_OS == OPT_OS_NONE
  160. SysTick_Config(CONF_CPU_FREQUENCY / 1000);
  161. #endif
  162. uart_init();
  163. #if CFG_TUSB_DEBUG >= 2
  164. uart_send_str(BOARD_NAME " UART initialized\n");
  165. tu_printf(BOARD_NAME " reset cause %#02x\n", RSTC->RCAUSE.reg);
  166. #endif
  167. // LED0 init
  168. gpio_set_pin_function(LED_PIN, GPIO_PIN_FUNCTION_OFF);
  169. gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT);
  170. board_led_write(0);
  171. #if CFG_TUSB_DEBUG >= 2
  172. uart_send_str(BOARD_NAME " LED pin configured\n");
  173. #endif
  174. // BTN0 init
  175. gpio_set_pin_function(BUTTON_PIN, GPIO_PIN_FUNCTION_OFF);
  176. gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN);
  177. gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP);
  178. #if CFG_TUSB_DEBUG >= 2
  179. uart_send_str(BOARD_NAME " Button pin configured\n");
  180. #endif
  181. #if CFG_TUSB_OS == OPT_OS_FREERTOS
  182. // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
  183. NVIC_SetPriority(USB_0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
  184. NVIC_SetPriority(USB_1_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
  185. NVIC_SetPriority(USB_2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
  186. NVIC_SetPriority(USB_3_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
  187. #endif
  188. #if TUSB_OPT_DEVICE_ENABLED
  189. #if CFG_TUSB_DEBUG >= 2
  190. uart_send_str(BOARD_NAME " USB device enabled\n");
  191. #endif
  192. /* USB clock init
  193. * The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock
  194. * for low speed and full speed operation.
  195. */
  196. hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK0_Val | GCLK_PCHCTRL_CHEN);
  197. hri_mclk_set_AHBMASK_USB_bit(MCLK);
  198. hri_mclk_set_APBBMASK_USB_bit(MCLK);
  199. // USB pin init
  200. gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT);
  201. gpio_set_pin_level(PIN_PA24, false);
  202. gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF);
  203. gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT);
  204. gpio_set_pin_level(PIN_PA25, false);
  205. gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF);
  206. gpio_set_pin_function(PIN_PA24, PINMUX_PA24H_USB_DM);
  207. gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP);
  208. #if CFG_TUSB_DEBUG >= 2
  209. uart_send_str(BOARD_NAME " USB device configured\n");
  210. #endif
  211. #endif
  212. }
  213. //--------------------------------------------------------------------+
  214. // Board porting API
  215. //--------------------------------------------------------------------+
  216. void board_led_write(bool state)
  217. {
  218. gpio_set_pin_level(LED_PIN, !state);
  219. }
  220. uint32_t board_button_read(void)
  221. {
  222. return (PORT->Group[1].IN.reg & 0x80000000) != 0x80000000;
  223. }
  224. int board_uart_read(uint8_t* buf, int len)
  225. {
  226. (void) buf; (void) len;
  227. return 0;
  228. }
  229. int board_uart_write(void const * buf, int len)
  230. {
  231. if (len < 0) {
  232. uart_send_str(buf);
  233. } else {
  234. uart_send_buffer(buf, len);
  235. }
  236. return len;
  237. }
  238. #if CFG_TUSB_OS == OPT_OS_NONE
  239. volatile uint32_t system_ticks = 0;
  240. void SysTick_Handler(void)
  241. {
  242. system_ticks++;
  243. }
  244. uint32_t board_millis(void)
  245. {
  246. return system_ticks;
  247. }
  248. #endif
  249. // Required by __libc_init_array in startup code if we are compiling using
  250. // -nostdlib/-nostartfiles.
  251. void _init(void)
  252. {
  253. }