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 67 static void Error_Handler(void) 68 { 69 for(;;); 70 } 71 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); 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 */ 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 */ 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 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 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 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 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 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 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 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 }