1 /*
2 * Copyright (C) 2019 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 /*
39 * Made for BlueKitchen by OneWave with <3
40 * Author: [email protected]
41 */
42
43 #define BTSTACK_FILE__ "main.c"
44
45 #include <stdio.h>
46
47 #include "main.h"
48 #include "otp.h"
49 #include "app_conf.h"
50
51 #include "FreeRTOS.h"
52 #include "task.h"
53
54 UART_HandleTypeDef hTuart = { 0 };
55 static RTC_HandleTypeDef hrtc = { 0 };
56
57 TaskHandle_t hbtstack_task;
58
59 static void SystemClock_Config(void);
60 static void PeriphClock_Config(void);
61 static void Tune_HSE( void );
62 static void Init_Exti( void );
63 static void Init_UART( void );
64 static void Init_RTC( void );
65
66
Error_Handler(void)67 static void Error_Handler(void)
68 {
69 for(;;);
70 }
71
Reset_BackupDomain(void)72 static void Reset_BackupDomain( void )
73 {
74 if ((LL_RCC_IsActiveFlag_PINRST() != 0) && (LL_RCC_IsActiveFlag_SFTRST() == 0))
75 {
76 HAL_PWR_EnableBkUpAccess(); /**< Enable access to the RTC registers */
77
78 /**
79 * Write twice the value to flush the APB-AHB bridge
80 * This bit shall be written in the register before writing the next one
81 */
82 HAL_PWR_EnableBkUpAccess();
83
84 __HAL_RCC_BACKUPRESET_FORCE();
85 __HAL_RCC_BACKUPRESET_RELEASE();
86 }
87
88 return;
89 }
90
91
92 /**
93 * @brief The application entry point.
94 * @retval int
95 */
96 void port_thread(void* args);
main(void)97 int main(void)
98 {
99 /* Reset of all peripherals, initializes the Systick. */
100 HAL_Init();
101
102 Reset_BackupDomain();
103
104 Tune_HSE();
105
106 SystemClock_Config();
107 PeriphClock_Config();
108
109 /* Init debug */
110 Init_UART();
111
112 Init_Exti();
113
114 Init_RTC();
115
116 xTaskCreate(port_thread, "btstack_thread", 2048, NULL, 1, &hbtstack_task);
117
118 vTaskStartScheduler();
119
120 /* We should never get here as control is now taken by the scheduler */
121 for(;;);
122 }
123
124 /**
125 * @brief System Clock Configuration
126 * @retval None
127 */
SystemClock_Config(void)128 void SystemClock_Config(void)
129 {
130 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
131 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
132 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
133
134 /** Configure LSE Drive Capability
135 */
136 __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
137
138 /** Configure the main internal regulator output voltage
139 */
140 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
141 /** Initializes the CPU, AHB and APB busses clocks
142 */
143 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI1
144 |RCC_OSCILLATORTYPE_HSE;
145 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
146 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
147 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
148 RCC_OscInitStruct.LSIState = RCC_LSI_ON;
149 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
150 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
151 {
152 Error_Handler();
153 }
154 /** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
155 */
156 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK4|RCC_CLOCKTYPE_HCLK2
157 |RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
158 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
159 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
160 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
161 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
162 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
163 RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV1;
164 RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1;
165
166 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
167 {
168 Error_Handler();
169 }
170 /** Initializes the peripherals clocks
171 */
172 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS|RCC_PERIPHCLK_RFWAKEUP
173 |RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART1
174 |RCC_PERIPHCLK_LPUART1;
175 PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
176 PeriphClkInitStruct.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1;
177 PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
178 PeriphClkInitStruct.RFWakeUpClockSelection = RCC_RFWKPCLKSOURCE_LSI;
179 PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSE;
180 PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE0;
181
182 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
183 {
184 Error_Handler();
185 }
186 }
187
188 /**
189 * @brief Peripheral Clock Configuration
190 * @retval None
191 */
PeriphClock_Config(void)192 void PeriphClock_Config(void)
193 {
194 /**
195 * Select LSE clock
196 * on wb series LSI is not enough accurate to maintain connection
197 */
198 LL_RCC_LSE_Enable();
199 while(!LL_RCC_LSE_IsReady());
200
201 /**
202 * Select wakeup source of BLE RF
203 */
204 LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE);
205
206 /**
207 * Switch OFF LSI
208 */
209 LL_RCC_LSI1_Disable();
210
211
212 /**
213 * Set RNG on HSI48
214 */
215 LL_RCC_HSI48_Enable();
216 while(!LL_RCC_HSI48_IsReady());
217 LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_HSI48);
218
219 return;
220 }
221
Tune_HSE(void)222 void Tune_HSE( void )
223 {
224 OTP_ID0_t * p_otp;
225
226 /**
227 * Read HSE_Tuning from OTP
228 */
229 p_otp = (OTP_ID0_t *) OTP_Read(0);
230 if (p_otp)
231 {
232 LL_RCC_HSE_SetCapacitorTuning(p_otp->hse_tuning);
233 }
234 }
235
Init_UART(void)236 static void Init_UART( void )
237 {
238 GPIO_InitTypeDef GPIO_InitStruct;
239
240 /* Peripheral clock enable */
241 DEBUG_USART_CLK_ENABLE();
242 DEBUG_USART_PORT_CLK_ENABLE();
243
244 /**USART GPIO Configuration */
245 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
246 GPIO_InitStruct.Pull = GPIO_NOPULL;
247 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
248 GPIO_InitStruct.Alternate = DEBUG_GPIO_AF;
249 /* DEBUG_USART_TX */
250 GPIO_InitStruct.Pin = DEBUG_USART_TX_Pin;
251 HAL_GPIO_Init(DEBUG_USART_TX_GPIO_Port, &GPIO_InitStruct);
252 /* DEBUG_USART_RX */
253 GPIO_InitStruct.Pin = DEBUG_USART_RX_Pin;
254 HAL_GPIO_Init(DEBUG_USART_RX_GPIO_Port, &GPIO_InitStruct);
255
256 /* USART Configuration */
257 hTuart.Instance = DEBUG_USART;
258 hTuart.Init.BaudRate = 115200;
259 hTuart.Init.WordLength = UART_WORDLENGTH_8B;
260 hTuart.Init.StopBits = UART_STOPBITS_1;
261 hTuart.Init.Parity = UART_PARITY_NONE;
262 hTuart.Init.Mode = UART_MODE_TX_RX;
263 hTuart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
264 hTuart.Init.OverSampling = UART_OVERSAMPLING_16;
265 hTuart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
266 hTuart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
267 if (HAL_UART_Init(&hTuart) != HAL_OK){
268 Error_Handler();
269 }
270 return;
271 }
272
Init_Exti(void)273 static void Init_Exti( void )
274 {
275 /**< Disable all wakeup interrupt on CPU1 except IPCC(36), HSEM(38) */
276 LL_EXTI_DisableIT_0_31(~0);
277 LL_EXTI_DisableIT_32_63( (~0) & (~(LL_EXTI_LINE_36 | LL_EXTI_LINE_38)) );
278
279 HAL_NVIC_SetPriority(IPCC_C1_RX_IRQn,5,0);
280 HAL_NVIC_SetPriority(IPCC_C1_TX_IRQn,5,0);
281
282 return;
283 }
284
Init_RTC(void)285 static void Init_RTC( void )
286 {
287 HAL_PWR_EnableBkUpAccess(); /**< Enable access to the RTC registers */
288
289 /**
290 * Write twice the value to flush the APB-AHB bridge
291 * This bit shall be written in the register before writing the next one
292 */
293 HAL_PWR_EnableBkUpAccess();
294
295 __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); /**< Select LSI as RTC Input */
296
297 __HAL_RCC_RTC_ENABLE(); /**< Enable RTC */
298
299 hrtc.Instance = RTC; /**< Define instance */
300
301 /**
302 * Set the Asynchronous prescaler
303 */
304 hrtc.Init.AsynchPrediv = CFG_RTC_ASYNCH_PRESCALER;
305 hrtc.Init.SynchPrediv = CFG_RTC_SYNCH_PRESCALER;
306 HAL_RTC_Init(&hrtc);
307
308 MODIFY_REG(RTC->CR, RTC_CR_WUCKSEL, CFG_RTC_WUCKSEL_DIVIDER);
309
310 /* RTC interrupt Init */
311 HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0, 0);
312 HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
313
314 return;
315 }
316
PreSleepProcessing(uint32_t ulExpectedIdleTime)317 void PreSleepProcessing(uint32_t ulExpectedIdleTime)
318 {
319 /* Called by the kernel before it places the MCU into a sleep mode because
320 configPRE_SLEEP_PROCESSING() is #defined to PreSleepProcessing().
321
322 NOTE: Additional actions can be taken here to get the power consumption
323 even lower. For example, peripherals can be turned off here, and then back
324 on again in the post sleep processing function. For maximum power saving
325 ensure all unused pins are in their lowest power state. */
326
327 /*
328 (*ulExpectedIdleTime) is set to 0 to indicate that PreSleepProcessing contains
329 its own wait for interrupt or wait for event instruction and so the kernel vPortSuppressTicksAndSleep
330 function does not need to execute the wfi instruction
331 */
332 ulExpectedIdleTime = 0;
333
334 /*Enter to sleep Mode using the HAL function HAL_PWR_EnterSLEEPMode with WFI instruction*/
335 HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
336 }
337
338
PostSleepProcessing(uint32_t ulExpectedIdleTime)339 void PostSleepProcessing(uint32_t ulExpectedIdleTime)
340 {
341 /* Called by the kernel when the MCU exits a sleep mode because
342 configPOST_SLEEP_PROCESSING is #defined to PostSleepProcessing(). */
343
344 /* Avoid compiler warnings about the unused parameter. */
345 (void) ulExpectedIdleTime;
346 }
347
vApplicationStackOverflowHook(TaskHandle_t xTask,signed char * pcTaskName)348 void vApplicationStackOverflowHook(TaskHandle_t xTask,
349 signed char *pcTaskName)
350 {
351 printf("stack overflow in task %s!\r\n", pcTaskName);
352 while (1);
353 }