Compare commits

...

35 Commits
ll ... master

Author SHA1 Message Date
Ondřej Hruška 1ea4cd124d add rudimentary calib param tuning screen (TODO negative offset support!) 1 year ago
Ondřej Hruška 6b94dcb5ee show chip overheat if over 70C 1 year ago
Ondřej Hruška 95f597c9ed make soc overheat visible in log + raise top limit to 90C 1 year ago
Ondřej Hruška 39e143d186 pid adjusts 1 year ago
Ondřej Hruška 0d79379438 PID edit screen 1 year ago
Ondřej Hruška d9f09c8ccb adjustments to calib procedure, now with PID used 1 year ago
Ondřej Hruška 991802b894 remove temp logging 1 year ago
Ondřej Hruška 60d15b8c07 add fancy hardfault handler, increase heater stack size 1 year ago
Ondřej Hruška f23f726b2d fix float formatting 1 year ago
Ondřej Hruška b6ccfd7019 fix manual override. 1 year ago
Ondřej Hruška dc445af419 fixes in calib 1 year ago
Ondřej Hruška 1331460ecb calibration mostly working 1 year ago
Ondřej Hruška 6749bb5f52 calib GUI WIP 1 year ago
Ondřej Hruška 08f1215c24 add two point calibration (no UI yet) 1 year ago
Ondřej Hruška 18655e437f ui improvements 1 year ago
Ondřej Hruška ccce0ff72f split gui file 1 year ago
Ondřej Hruška 415a6cb06c some cz unicode in 5x7 1 year ago
Ondřej Hruška 90832fd2f4 move GUI safety check to gui loop (not blit) 1 year ago
Ondřej Hruška 170be709fe menu sliding to last px 1 year ago
Ondřej Hruška 088b047b39 some comments 1 year ago
Ondřej Hruška edd003a541 fixes for partly off-screen bitmap, remove temporary debug changes 1 year ago
Ondřej Hruška 0d9565dbb7 partial fix for text drawing in wrong row 1 year ago
Ondřej Hruška fcc37515c5 menu sliding, add knob prescaller 1 year ago
Ondřej Hruška 64c7d3a94a screens cleanup, doc comments 1 year ago
Ondřej Hruška 22b1ba3921 menu fixes, add periodic tick event, add repaint-when-needed 1 year ago
Ondřej Hruška b0df411c56 menu improvements, add generic menu func 1 year ago
Ondřej Hruška 6048bdf115 base of menu system 1 year ago
Ondřej Hruška b397856366 add safety system, stub of new gui task 1 year ago
Ondřej Hruška 0a0ccf7bc3 implement EEPROM emulation 1 year ago
Ondřej Hruška 56cae1abdb events and exti 1 year ago
Ondřej Hruška 091d6c5648 timer based ADC triggering 1 year ago
Ondřej Hruška bff7f6e916 move adc sampling to DMA TC interrupt 1 year ago
Ondřej Hruška 6eb18ac72e Merge branch 'll' 1 year ago
Ondřej Hruška 8376f0b5eb fixes 1 year ago
Ondřej Hruška 7e99e2cc6c thin printf, but buggy 1 year ago
  1. 40
      .mxproject
  2. 87
      BluepillTrouba.ioc
  3. 4
      Core/Inc/FreeRTOSConfig.h
  4. 50
      Core/Inc/crc.h
  5. 14
      Core/Inc/main.h
  6. 2
      Core/Inc/stm32f1xx_it.h
  7. 1
      Core/Inc/tim.h
  8. 158
      Core/Src/Gui/app_gui.c
  9. 88
      Core/Src/Gui/app_gui.h
  10. 38
      Core/Src/Gui/gui_event.h
  11. 217
      Core/Src/Gui/screen_calib_edit.c
  12. 242
      Core/Src/Gui/screen_calibration.c
  13. 44
      Core/Src/Gui/screen_home.c
  14. 78
      Core/Src/Gui/screen_manual.c
  15. 35
      Core/Src/Gui/screen_manual_menu.c
  16. 116
      Core/Src/Gui/screen_menu.c
  17. 30
      Core/Src/Gui/screen_menu.h
  18. 194
      Core/Src/Gui/screen_pid_tuning.c
  19. 10
      Core/Src/adc.c
  20. 2
      Core/Src/app_buzzer.c
  21. 14
      Core/Src/app_gui.c
  22. 10
      Core/Src/app_gui.h
  23. 136
      Core/Src/app_heater.c
  24. 28
      Core/Src/app_heater.h
  25. 64
      Core/Src/app_knob.c
  26. 5
      Core/Src/app_knob.h
  27. 258
      Core/Src/app_main.c
  28. 5
      Core/Src/app_oled.c
  29. 21
      Core/Src/app_pid.c
  30. 3
      Core/Src/app_pid.h
  31. 66
      Core/Src/app_safety.c
  32. 30
      Core/Src/app_safety.h
  33. 553
      Core/Src/app_temp.c
  34. 17
      Core/Src/app_temp.h
  35. 49
      Core/Src/crc.c
  36. 25
      Core/Src/ee_addresses.h
  37. 39
      Core/Src/freertos.c
  38. 24
      Core/Src/gpio.c
  39. 203
      Core/Src/main.c
  40. 339
      Core/Src/stm32f1xx_it.c
  41. 68
      Core/Src/tim.c
  42. 15
      Core/Src/transmute.h
  43. 52
      Core/Src/uart_stdout.c
  44. 8
      Core/Src/uart_stdout.h
  45. 18
      Core/Src/usart.c
  46. 204
      Drivers/STM32F1xx_HAL_Driver/Inc/stm32f1xx_ll_crc.h
  47. 108
      Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_crc.c
  48. 2410
      Lib/EEPROM_Emul/Core/eeprom_emul.c
  49. 107
      Lib/EEPROM_Emul/Core/eeprom_emul.h
  50. 53
      Lib/EEPROM_Emul/Core/eeprom_emul_conf.h
  51. 4
      Lib/EEPROM_Emul/Core/eeprom_emul_types.h
  52. 258
      Lib/EEPROM_Emul/Porting/STM32C0/flash_interface.c
  53. 125
      Lib/EEPROM_Emul/Porting/STM32C0/flash_interface.h
  54. 173
      Lib/EEPROM_Emul/Porting/STM32F1/flash_interface.c
  55. 30
      Lib/EEPROM_Emul/Porting/STM32F1/flash_interface.h
  56. 265
      Lib/EEPROM_Emul/Porting/STM32G0/flash_interface.c
  57. 125
      Lib/EEPROM_Emul/Porting/STM32G0/flash_interface.h
  58. 280
      Lib/EEPROM_Emul/Porting/STM32G4/flash_interface.c
  59. 125
      Lib/EEPROM_Emul/Porting/STM32G4/flash_interface.h
  60. 279
      Lib/EEPROM_Emul/Porting/STM32L4/flash_interface.c
  61. 267
      Lib/EEPROM_Emul/Porting/STM32L5/flash_interface.c
  62. 126
      Lib/EEPROM_Emul/Porting/STM32L5/flash_interface.h
  63. 299
      Lib/EEPROM_Emul/Porting/STM32U5/flash_interface.c
  64. 126
      Lib/EEPROM_Emul/Porting/STM32U5/flash_interface.h
  65. 375
      Lib/EEPROM_Emul/Porting/STM32WB/flash_interface.c
  66. 142
      Lib/EEPROM_Emul/Porting/STM32WB/flash_interface.h
  67. 207
      Lib/EEPROM_Emul/Porting/STM32WL/flash_interface.c
  68. 134
      Lib/EEPROM_Emul/Porting/STM32WL/flash_interface.h
  69. 1082
      Lib/snprintf/snprintf.c
  70. 44
      Lib/snprintf/snprintf.h
  71. 2
      Lib/ufb/Inc/ufb/fb_text.h
  72. 17
      Lib/ufb/Src/fb_text.c
  73. 1
      Lib/ufb/Src/font_35.inc.c
  74. 20
      Lib/ufb/Src/font_57.inc.c
  75. 7
      Lib/ufb/Src/fontedit_35.c
  76. 268
      Lib/ufb/Src/fontedit_57.c
  77. 24
      Lib/ufb/Src/framebuffer.c
  78. 6
      Lib/ufb/Src/main.c
  79. 44
      Makefile
  80. 10
      STM32F103C8Tx_FLASH.ld

File diff suppressed because one or more lines are too long

@ -3,8 +3,9 @@ ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_0
ADC1.Channel-1\#ChannelRegularConversion=ADC_CHANNEL_1
ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_TEMPSENSOR
ADC1.Channel-3\#ChannelRegularConversion=ADC_CHANNEL_VREFINT
ADC1.ContinuousConvMode=ENABLE
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ContinuousConvMode,Rank-1\#ChannelRegularConversion,Channel-1\#ChannelRegularConversion,SamplingTime-1\#ChannelRegularConversion,Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,Rank-3\#ChannelRegularConversion,Channel-3\#ChannelRegularConversion,SamplingTime-3\#ChannelRegularConversion,NbrOfConversion
ADC1.ContinuousConvMode=DISABLE
ADC1.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T1_CC1
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ContinuousConvMode,Rank-1\#ChannelRegularConversion,Channel-1\#ChannelRegularConversion,SamplingTime-1\#ChannelRegularConversion,Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,Rank-3\#ChannelRegularConversion,Channel-3\#ChannelRegularConversion,SamplingTime-3\#ChannelRegularConversion,NbrOfConversion,ExternalTrigConv
ADC1.NbrOfConversion=4
ADC1.NbrOfConversionFlag=1
ADC1.Rank-0\#ChannelRegularConversion=1
@ -30,9 +31,9 @@ Dma.RequestsNb=1
FREERTOS.FootprintOK=true
FREERTOS.IPParameters=Tasks01,configUSE_MALLOC_FAILED_HOOK,configCHECK_FOR_STACK_OVERFLOW,configUSE_NEWLIB_REENTRANT,FootprintOK,Mutexes01,Queues01,Timers01,configUSE_TRACE_FACILITY,configUSE_STATS_FORMATTING_FUNCTIONS,configENABLE_BACKWARD_COMPATIBILITY
FREERTOS.Mutexes01=heaterMutex,Static,heaterMutexControlBlock
FREERTOS.Queues01=guiEventQue,16,8,1,Static,guiEventQueBuffer,guiEventQueControlBlock
FREERTOS.Queues01=guiEventQue,32,1,1,Static,guiEventQueBuffer,guiEventQueControlBlock
FREERTOS.Tasks01=mainTsk,24,256,app_task_main,As weak,NULL,Static,defaultTaskBuffer,defaultTaskControlBlock;heaterTsk,24,128,app_task_heater,As external,NULL,Static,heaterTskBuffer,heaterTskControlBlock;guiTsk,40,256,app_task_gui,As external,NULL,Static,guiTskBuffer,guiTskControlBlock
FREERTOS.Timers01=beepTimer,app_beep_end,osTimerOnce,As external,NULL,Static,beepTimerControlBlock
FREERTOS.Timers01=beepTimer,app_beep_end,osTimerOnce,As external,NULL,Static,beepTimerControlBlock;buttonPushTimer,app_push_debounce,osTimerOnce,As external,1,Static,buttonPushTimerControlBlock;buttonReleaseTimer,app_push_debounce,osTimerOnce,As external,0,Static,buttonReleaseTimerControlBlock
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=2
FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=0
FREERTOS.configUSE_MALLOC_FAILED_HOOK=1
@ -40,7 +41,7 @@ FREERTOS.configUSE_NEWLIB_REENTRANT=1
FREERTOS.configUSE_STATS_FORMATTING_FUNCTIONS=1
FREERTOS.configUSE_TRACE_FACILITY=1
File.Version=6
GPIO.groupedBy=Group By Peripherals
GPIO.groupedBy=Show All
IWDG.IPParameters=Prescaler,Reload
IWDG.Prescaler=IWDG_PRESCALER_256
IWDG.Reload=624
@ -48,18 +49,20 @@ KeepUserPlacement=false
Mcu.CPN=STM32F103C8T6
Mcu.Family=STM32F1
Mcu.IP0=ADC1
Mcu.IP1=DMA
Mcu.IP10=TIM4
Mcu.IP11=USART1
Mcu.IP2=FREERTOS
Mcu.IP3=IWDG
Mcu.IP4=NVIC
Mcu.IP5=RCC
Mcu.IP6=SPI2
Mcu.IP7=SYS
Mcu.IP8=TIM2
Mcu.IP9=TIM3
Mcu.IPNb=12
Mcu.IP1=CRC
Mcu.IP10=TIM2
Mcu.IP11=TIM3
Mcu.IP12=TIM4
Mcu.IP13=USART1
Mcu.IP2=DMA
Mcu.IP3=FREERTOS
Mcu.IP4=IWDG
Mcu.IP5=NVIC
Mcu.IP6=RCC
Mcu.IP7=SPI2
Mcu.IP8=SYS
Mcu.IP9=TIM1
Mcu.IPNb=14
Mcu.Name=STM32F103C(8-B)Tx
Mcu.Package=LQFP48
Mcu.Pin0=PC13-TAMPER-RTC
@ -73,12 +76,15 @@ Mcu.Pin15=PB7
Mcu.Pin16=PB8
Mcu.Pin17=VP_ADC1_TempSens_Input
Mcu.Pin18=VP_ADC1_Vref_Input
Mcu.Pin19=VP_FREERTOS_VS_CMSIS_V2
Mcu.Pin19=VP_CRC_VS_CRC
Mcu.Pin2=PA1
Mcu.Pin20=VP_IWDG_VS_IWDG
Mcu.Pin21=VP_SYS_VS_Systick
Mcu.Pin22=VP_TIM2_VS_ClockSourceINT
Mcu.Pin23=VP_TIM3_VS_ClockSourceINT
Mcu.Pin20=VP_FREERTOS_VS_CMSIS_V2
Mcu.Pin21=VP_IWDG_VS_IWDG
Mcu.Pin22=VP_SYS_VS_Systick
Mcu.Pin23=VP_TIM1_VS_ClockSourceINT
Mcu.Pin24=VP_TIM1_VS_no_output1
Mcu.Pin25=VP_TIM2_VS_ClockSourceINT
Mcu.Pin26=VP_TIM3_VS_ClockSourceINT
Mcu.Pin3=PA6
Mcu.Pin4=PB0
Mcu.Pin5=PB1
@ -86,16 +92,16 @@ Mcu.Pin6=PB10
Mcu.Pin7=PB13
Mcu.Pin8=PB15
Mcu.Pin9=PA9
Mcu.PinsNb=24
Mcu.PinsNb=27
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F103C8Tx
MxCube.Version=6.5.0
MxDb.Version=DB.6.0.50
NVIC.ADC1_2_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:true
NVIC.DMA1_Channel1_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:true
NVIC.EXTI9_5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:true
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:true
@ -109,13 +115,13 @@ NVIC.SavedSystickIrqHandlerGenerated=true
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:false\:true\:true
NVIC.TIM4_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:true
PA0-WKUP.GPIOParameters=GPIO_Label
PA0-WKUP.GPIO_Label=ADC_PT100
PA0-WKUP.Signal=ADCx_IN0
PA1.GPIOParameters=GPIO_Label
PA1.GPIO_Label=ADC_SENSR
PA1.Locked=true
PA1.Signal=ADCx_IN1
PA10.GPIOParameters=GPIO_PuPd
PA10.GPIO_PuPd=GPIO_PULLUP
PA10.Mode=Asynchronous
PA10.Signal=USART1_RX
PA13.Locked=true
@ -128,6 +134,8 @@ PA15.GPIOParameters=GPIO_Speed,GPIO_Label
PA15.GPIO_Label=BUZZER
PA15.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
PA15.Signal=S_TIM2_CH1_ETR
PA6.GPIOParameters=GPIO_Label
PA6.GPIO_Label=PWM_HEATER
PA6.Locked=true
PA6.Signal=S_TIM3_CH1
PA9.Mode=Asynchronous
@ -158,10 +166,12 @@ PB7.GPIOParameters=GPIO_PuPd,GPIO_Label
PB7.GPIO_Label=KNOB_B
PB7.GPIO_PuPd=GPIO_PULLUP
PB7.Signal=S_TIM4_CH2
PB8.GPIOParameters=GPIO_Label
PB8.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
PB8.GPIO_Label=KNOB_PUSH
PB8.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_RISING_FALLING
PB8.GPIO_PuPd=GPIO_PULLUP
PB8.Locked=true
PB8.Signal=GPIO_Input
PB8.Signal=GPXTI8
PC13-TAMPER-RTC.GPIOParameters=GPIO_Label
PC13-TAMPER-RTC.GPIO_Label=LED
PC13-TAMPER-RTC.Locked=true
@ -194,7 +204,7 @@ ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=Makefile
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_IWDG_Init-IWDG-false-LL-true,4-MX_USART1_UART_Init-USART1-false-LL-true,5-MX_ADC1_Init-ADC1-false-LL-true,6-MX_DMA_Init-DMA-false-LL-true,7-MX_TIM4_Init-TIM4-false-LL-true,8-MX_TIM2_Init-TIM2-false-LL-true,9-MX_TIM3_Init-TIM3-false-LL-true,10-MX_SPI2_Init-SPI2-false-LL-true
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-LL-false,2-MX_GPIO_Init-GPIO-false-LL-true,3-MX_IWDG_Init-IWDG-false-LL-true,4-MX_USART1_UART_Init-USART1-false-LL-true,5-MX_ADC1_Init-ADC1-false-LL-true,6-MX_DMA_Init-DMA-false-LL-true,7-MX_TIM4_Init-TIM4-false-LL-true,8-MX_TIM2_Init-TIM2-false-LL-true,9-MX_TIM3_Init-TIM3-false-LL-true,10-MX_SPI2_Init-SPI2-false-LL-true,11-MX_TIM1_Init-TIM1-false-LL-true,12-MX_CRC_Init-CRC-false-LL-true
RCC.ADCFreqValue=8000000
RCC.ADCPresc=RCC_ADCPCLK2_DIV8
RCC.AHBFreq_Value=64000000
@ -222,6 +232,8 @@ SH.ADCx_IN0.0=ADC1_IN0,IN0
SH.ADCx_IN0.ConfNb=1
SH.ADCx_IN1.0=ADC1_IN1,IN1
SH.ADCx_IN1.ConfNb=1
SH.GPXTI8.0=GPIO_EXTI8
SH.GPXTI8.ConfNb=1
SH.S_TIM2_CH1_ETR.0=TIM2_CH1,PWM Generation1 CH1
SH.S_TIM2_CH1_ETR.ConfNb=1
SH.S_TIM3_CH1.0=TIM3_CH1,PWM Generation1 CH1
@ -236,16 +248,23 @@ SPI2.Direction=SPI_DIRECTION_2LINES
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler
SPI2.Mode=SPI_MODE_MASTER
SPI2.VirtualType=VM_MASTER
TIM1.Channel-PWM\ Generation1\ No\ Output=TIM_CHANNEL_1
TIM1.IPParameters=Prescaler,Period,TIM_MasterOutputTrigger,Channel-PWM Generation1 No Output,Pulse-PWM Generation1 No Output
TIM1.Period=10
TIM1.Prescaler=64000
TIM1.Pulse-PWM\ Generation1\ No\ Output=1
TIM1.TIM_MasterOutputTrigger=TIM_TRGO_OC1REF
TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM2.IPParameters=Channel-PWM Generation1 CH1,Prescaler
TIM2.Prescaler=2
TIM3.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM3.IPParameters=Channel-PWM Generation1 CH1,Prescaler,Pulse-PWM Generation1 CH1,Period
TIM3.Period=64000
TIM3.Prescaler=2000
TIM3.Prescaler=1000
TIM3.Pulse-PWM\ Generation1\ CH1=0
TIM4.IC1Filter=15
TIM4.IC2Filter=15
TIM4.IPParameters=IC2Filter,Prescaler
TIM4.IPParameters=IC2Filter,Prescaler,IC1Filter
TIM4.Prescaler=0
USART1.IPParameters=VirtualMode,Mode
USART1.Mode=MODE_TX_RX
@ -254,12 +273,18 @@ VP_ADC1_TempSens_Input.Mode=IN-TempSens
VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input
VP_ADC1_Vref_Input.Mode=IN-Vrefint
VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input
VP_CRC_VS_CRC.Mode=CRC_Activate
VP_CRC_VS_CRC.Signal=CRC_VS_CRC
VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
VP_IWDG_VS_IWDG.Mode=IWDG_Activate
VP_IWDG_VS_IWDG.Signal=IWDG_VS_IWDG
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM1_VS_ClockSourceINT.Mode=Internal
VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
VP_TIM1_VS_no_output1.Mode=PWM Generation1 No Output
VP_TIM1_VS_no_output1.Signal=TIM1_VS_no_output1
VP_TIM2_VS_ClockSourceINT.Mode=Internal
VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT
VP_TIM3_VS_ClockSourceINT.Mode=Internal

@ -137,8 +137,8 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
#include <stdio.h>
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); printf("configASSERT "__FILE__":%d\r\n",__LINE__); for( ;; );}
#include "snprintf.h"
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); PRINTF("FreeRTOS assert @ %s:%d\r\n", __FILE__, __LINE__); for( ;; );}
/* USER CODE END 1 */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS

@ -0,0 +1,50 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file crc.h
* @brief This file contains all the function prototypes for
* the crc.c file
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __CRC_H__
#define __CRC_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_CRC_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __CRC_H__ */

@ -16,10 +16,6 @@
*
******************************************************************************
*/
// this is a hack needed for CLion - placed here so cubemx does not overwrite it
#ifndef USE_FULL_LL_DRIVER
#define USE_FULL_LL_DRIVER 1
#endif
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
@ -33,6 +29,7 @@ extern "C" {
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_adc.h"
#include "stm32f1xx_ll_crc.h"
#include "stm32f1xx_ll_dma.h"
#include "stm32f1xx_ll_iwdg.h"
#include "stm32f1xx_ll_rcc.h"
@ -54,6 +51,10 @@ extern "C" {
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
extern void app_emergency_stop(void);
#define __weak __attribute__((weak))
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
@ -81,10 +82,10 @@ void Error_Handler(void);
/* Private defines -----------------------------------------------------------*/
#define LED_Pin LL_GPIO_PIN_13
#define LED_GPIO_Port GPIOC
#define ADC_PT100_Pin LL_GPIO_PIN_0
#define ADC_PT100_GPIO_Port GPIOA
#define ADC_SENSR_Pin LL_GPIO_PIN_1
#define ADC_SENSR_GPIO_Port GPIOA
#define PWM_HEATER_Pin LL_GPIO_PIN_6
#define PWM_HEATER_GPIO_Port GPIOA
#define OLED_CS_Pin LL_GPIO_PIN_0
#define OLED_CS_GPIO_Port GPIOB
#define OLED_DC_Pin LL_GPIO_PIN_1
@ -99,6 +100,7 @@ void Error_Handler(void);
#define KNOB_B_GPIO_Port GPIOB
#define KNOB_PUSH_Pin LL_GPIO_PIN_8
#define KNOB_PUSH_GPIO_Port GPIOB
#define KNOB_PUSH_EXTI_IRQn EXTI9_5_IRQn
#ifndef NVIC_PRIORITYGROUP_0
#define NVIC_PRIORITYGROUP_0 ((uint32_t)0x00000007) /*!< 0 bit for pre-emption priority,
4 bits for subpriority */

@ -54,7 +54,7 @@ void UsageFault_Handler(void);
void DebugMon_Handler(void);
void SysTick_Handler(void);
void DMA1_Channel1_IRQHandler(void);
void ADC1_2_IRQHandler(void);
void EXTI9_5_IRQHandler(void);
void TIM4_IRQHandler(void);
/* USER CODE BEGIN EFP */

@ -36,6 +36,7 @@ extern "C" {
/* USER CODE END Private defines */
void MX_TIM1_Init(void);
void MX_TIM2_Init(void);
void MX_TIM3_Init(void);
void MX_TIM4_Init(void);

@ -0,0 +1,158 @@
/**
* TODO file description
*/
#include <stdbool.h>
#include <string.h>
#include "app_gui.h"
#include "app_buzzer.h"
#include "app_temp.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "ufb/framebuffer.h"
#include "ufb/fb_text.h"
#include "app_safety.h"
#include "app_heater.h"
struct State s_app = {};
/** Get push time (while held) */
uint32_t push_time() {
return s_app.pushed ? (xTaskGetTickCount() - s_app.push_time) : 0;
}
/** Schedule paint (the screen func will be called with the PAINT event argument */
void request_paint() {
s_app.paint_needed = true;
}
/** Draw the common overlay / HUD (with temperatures and heater status) */
static void draw_common_overlay();
char stmp[100];
/** Main loop */
void app_task_gui(void *argument) {
// Wait until inited
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
PUTS("GUI task starts\r\n");
s_app.last_tick_time = xTaskGetTickCount();
switch_screen(screen_home, true);
while (1) {
uint32_t message = GUI_EVENT_NONE;
int32_t ticks_remain = (int32_t) pdMS_TO_TICKS(10) - (int32_t) (xTaskGetTickCount() - s_app.last_tick_time);
if (ticks_remain < 0) {
ticks_remain = 0;
}
osMessageQueueGet(guiEventQueHandle, &message, NULL, ticks_remain);
if (message == GUI_EVENT_KNOB_PLUS) {
if (s_app.up_prescaller) {
s_app.up_prescaller = 0;
// let this through
} else {
// consume this
s_app.down_prescaller = 0;
s_app.up_prescaller = 1;
message = GUI_EVENT_NONE;
}
} else if (message == GUI_EVENT_KNOB_MINUS) {
if (s_app.down_prescaller) {
s_app.down_prescaller = 0;
// let this through
} else {
// consume this
s_app.up_prescaller = 0;
s_app.down_prescaller = 1;
message = GUI_EVENT_NONE;
}
}
uint32_t tickNow = xTaskGetTickCount();
// 10ms tick event
if (tickNow - s_app.last_tick_time > pdMS_TO_TICKS(10)) {
s_app.screen(GUI_EVENT_SCREEN_TICK);
s_app.last_tick_time = tickNow;
}
if (tickNow - s_app.last_read_temp_time > pdMS_TO_TICKS(250)) {
s_app.oven_temp = app_temp_read_oven();
//s_app.soc_temp = app_temp_read_soc();
request_paint();
s_app.last_read_temp_time = tickNow;
}
switch (message) {
case GUI_EVENT_KNOB_PRESS:
s_app.pushed = true;
s_app.push_time = tickNow;
break;
case GUI_EVENT_KNOB_RELEASE:
s_app.pushed = false;
if (s_app.initial_pushed) {
s_app.initial_pushed = false;
message = GUI_EVENT_NONE;
}
break;
}
if (message != GUI_EVENT_NONE) {
s_app.screen(message);
}
app_safety_pass_display_updating();
if (s_app.paint_needed) {
s_app.paint_needed = false;
fb_clear();
draw_common_overlay();
s_app.screen(GUI_EVENT_PAINT);
fb_blit();
}
}
}
/** Switch to a different screen handler.
* If "init" is true, immediately call it with the init event. */
void switch_screen(screen_t pScreen, bool init) {
PRINTF("Screen = %p, init=%d\r\n", pScreen, init);
s_app.initial_pushed = s_app.pushed;
s_app.screen = pScreen;
// clear the union field
request_paint();
if (init) {
pScreen(GUI_EVENT_SCREEN_INIT);
}
}
/** Draw GUI common to all screens */
static void draw_common_overlay() {
SPRINTF(stmp, "%5.1f°C →%3d°C", app_temp_read_oven(), (int) app_heater_get_target());
fb_text(3, 3, stmp, FONT_3X5, 1);
float soc = app_temp_read_soc();
if (soc > 70) {
SPRINTF(stmp, "! CHIP %d°C !", (int) soc);
fb_text(3, 14, stmp, FONT_3X5, 1);
}
if (app_heater_get_state()) {
fb_frame(0, 0, FBW, 11, 1, 1);
float perc = app_heater_get_percent();
fb_hline(0, 12, (fbpos_t) ((float)FBW * (perc / 100.0f)), 1);
}
}
/** Play input sound effect if this is an input event */
void input_sound_effect() {
app_buzzer_beep();
}

@ -0,0 +1,88 @@
/**
* TODO file description
*/
#ifndef BLUEPILLTROUBA_APP_GUI_H
#define BLUEPILLTROUBA_APP_GUI_H
#include "cmsis_os2.h"
#include <stdbool.h>
#include "gui_event.h"
extern char stmp[100];
void app_task_gui(void *argument);
/**
* Screen callback type. The event is either INIT, PAINT, or one of the input events.
*/
typedef void (*screen_t)(GuiEvent event);
/** Input beep (push or knob turn) */
void input_sound_effect();
/** Switch to a different screen. Handles initial push state handling (so release
* does not cause a "click" event).
*
* @param pScreen - screen to switch to
* @param init - call the INIT event immediately after
*/
void switch_screen(screen_t pScreen, bool init);
void request_paint();
uint32_t push_time();
// prototypes for screen handlers
void screen_home(GuiEvent event);
void screen_manual(GuiEvent event);
void screen_manual_menu(GuiEvent event);
void screen_calibration(GuiEvent event);
void screen_pid_tuning(GuiEvent event);
void screen_calib_edit(GuiEvent event);
struct State {
/// Latest oven temp readout
float oven_temp;
//float soc_temp;
// manual mode controls
/// Currently set target temp
int set_temp;
/// Heater enabled status (only visual)
bool heater_enabled;
/// Prescaller for the knob, CCW direction.
/// Event increments this counter and resets the other. Knob turn event is generated on overflow.
bool down_prescaller;
/// Prescaller for the knob, CW direction
/// See `down_prescaller`
bool up_prescaller;
/// Curent status of the push button
bool pushed;
/// Repaint was requested from the screen code
bool paint_needed;
/// Timestamp of the last GUI tick
uint32_t last_tick_time;
/// Timestamp when the button was pushed
uint32_t push_time;
/// Timestamp when we last read oven temperature for display
uint32_t last_read_temp_time;
/// true if the button is still held since init (i.e. the push action should not work as "enter")
bool initial_pushed;
/// Pointer to the currently active screen func
screen_t screen;
};
extern struct State s_app;
#endif //BLUEPILLTROUBA_APP_GUI_H

@ -0,0 +1,38 @@
//
// Created by MightyPork on 2023/04/09.
//
#ifndef TOASTER_OVEN_BLUEPILL_GUI_EVENT_H
#define TOASTER_OVEN_BLUEPILL_GUI_EVENT_H
#include "cmsis_os2.h"
extern osThreadId_t guiTskHandle;
extern osMessageQueueId_t guiEventQueHandle;
// sent through the notify queue
typedef enum GuiEvent {
/// No event, zero; This is a default value.
GUI_EVENT_NONE = 0,
/// Cause redraw
GUI_EVENT_PAINT = 0,
/// Used as the argument when initing a screen
GUI_EVENT_SCREEN_INIT = 1,
/// Time tick, used to carry timing to the screen functions.
/// This tick has 10ms interval
GUI_EVENT_SCREEN_TICK = 2,
/// Knob rotate CW
GUI_EVENT_KNOB_PLUS,
/// Knob rotate CCW
GUI_EVENT_KNOB_MINUS,
/// Knob pressed
GUI_EVENT_KNOB_PRESS,
/// Knob released
GUI_EVENT_KNOB_RELEASE,
/// Temperature readings changed.
/// Not really an input event, but it should trigger a redraw
GUI_EVENT_TEMP_CHANGE,
} GuiEvent;
#endif //TOASTER_OVEN_BLUEPILL_GUI_EVENT_H

@ -0,0 +1,217 @@
//
// Created by MightyPork on 2023/05/06
//
#include <string.h>
#include "app_gui.h"
#include "app_heater.h"
#include "ufb/fb_text.h"
#include "snprintf.h"
#include "app_temp.h"
static void apply_calib(bool temporary);
static struct calib_tuning_state {
uint8_t digits[6 * 4]; // a b l r
int cursor; // the digit under cursor (range 0-17)
bool digit_editing; // true if we are editing a digit
} s_tuning;
static void draw_digit_row(int row) {
fbpos_t x = (FBW - (6 * 7 - 1)) / 2;
fbpos_t y = 30 + row * 10;
char buf2[2] = {};
int numofs = row * 6;
const char * labels[4] = {"a","b","L", "R"};
const int decimal_pos[4] = {2, 0, 3, 3};
fb_text(FBW - 4, y + 2, labels[row], FONT_3X5, 1);
bool significant = row == 1;
for (int i = 0; i < 6; i++) {
if (i >= decimal_pos[row]) significant = 1;
int val = s_tuning.digits[numofs + i];
if (val != 0) {
significant = true;
}
buf2[0] = '0' + val;
if (s_tuning.cursor == numofs + i) {
if (s_tuning.digit_editing) {
fb_rect(x-1, y-1, 5+2, 7+2, 1);
fb_text(x, y, buf2, 0, 0);
} else {
fb_hline(x, y + 8, 5, 1);
if (significant) fb_text(x, y, buf2, 0, 1);
}
} else {
if (significant) fb_text(x, y, buf2, 0, 1);
}
x += 6;
if (i == decimal_pos[row]) {
fb_text(x, y, ".", 0, 1);
x += 6;
}
}
}
void screen_calib_edit(GuiEvent event)
{
float A, B, L, R;
uint32_t Ai, Bi, Li, Ri;
if (event == GUI_EVENT_SCREEN_INIT) {
memset(&s_tuning, 0, sizeof(s_tuning));
app_temp_get_calib(&A, &B, &L, &R);
app_temp_backup_calib();
Ai = (uint32_t)(A * 1000.f);
Bi = (uint32_t)(B * 100000.f);
Li = (uint32_t)(L * 100.f);
Ri = (uint32_t)(R * 100.f);
char buf[25];
SNPRINTF(buf, 25, "%06lu%06lu%06lu%06lu", Ai, Bi, Li, Ri);
for(int i = 0; i < 6*4; i++) {
s_tuning.digits[i] = buf[i] - '0';
}
}
switch (event) {
case GUI_EVENT_PAINT: {
fb_text(FBW / 2, 16, "Kalibrace", TEXT_CENTER, 1);
draw_digit_row(0);
draw_digit_row(1);
draw_digit_row(2);
draw_digit_row(3);
//68
#define BTNS_TOP 72
if (s_tuning.cursor == 24) {
fb_rect(0, BTNS_TOP, FBW, 9, 1);
}
fb_text(FBW / 2, BTNS_TOP + 1, "Zrušit", TEXT_CENTER, s_tuning.cursor != 24);
if (s_tuning.cursor == 25) {
fb_rect(0, BTNS_TOP + 9, FBW, 9, 1);
}
fb_text(FBW / 2, BTNS_TOP + 1 + 9, "Uložit", TEXT_CENTER, s_tuning.cursor != 25);
fb_text(2, FBH - 8 * (1 + (s_tuning.cursor < 24)), s_tuning.digit_editing ? "←→Hodnota" : "←→Kurzor", 0, 1);
if (s_tuning.cursor < 24) {
fb_text(2, FBH - 8 * 1, s_tuning.digit_editing ? "> Potvrdit" : "> Změnit", 0, 1);
}
return;
}
case GUI_EVENT_KNOB_PLUS: {
input_sound_effect();
request_paint();
if (s_tuning.digit_editing) {
if (s_tuning.digits[s_tuning.cursor] == 9) {
s_tuning.digits[s_tuning.cursor] = 0;
} else {
s_tuning.digits[s_tuning.cursor]++;
}
apply_calib(false);
} else {
// 24 - cancel
// 25 - save
s_tuning.cursor++;
if (s_tuning.cursor >= 24) {
s_tuning.digit_editing = false;
}
if (s_tuning.cursor > 25) {
s_tuning.cursor = 0;
}
}
break;
}
case GUI_EVENT_KNOB_MINUS: {
input_sound_effect();
request_paint();
if (s_tuning.digit_editing) {
if (s_tuning.digits[s_tuning.cursor] == 0) {
s_tuning.digits[s_tuning.cursor] = 9;
} else {
s_tuning.digits[s_tuning.cursor]--;
}
apply_calib(false);
} else {
// 24 - cancel
// 25 - save
if (s_tuning.cursor == 0) {
s_tuning.cursor = 25;
s_tuning.digit_editing = false;
} else {
s_tuning.cursor--;
}
}
break;
}
case GUI_EVENT_KNOB_RELEASE: {
if (s_tuning.cursor < 24) {
s_tuning.digit_editing = !s_tuning.digit_editing;
} else if (s_tuning.cursor == 24) {
// cancel
app_temp_restore_calib();
switch_screen(screen_home, true);
} else if (s_tuning.cursor == 25) {
// save
apply_calib(true);
switch_screen(screen_home, true);
}
break;
}
}
}
static void apply_calib(bool temporary) {
float A, B, L, R;
uint32_t Ai, Bi, Li, Ri;
Ai = Bi = Li = Ri = 0;
for(int i = 0; i < 6; i++) {
Ai *= 10;
Ai += s_tuning.digits[i];
}
for(int i = 6; i < 12; i++) {
Bi *= 10;
Bi += s_tuning.digits[i];
}
for(int i = 12; i < 18; i++) {
Li *= 10;
Li += s_tuning.digits[i];
}
for(int i = 18; i < 24; i++) {
Ri *= 10;
Ri += s_tuning.digits[i];
}
A = ((float) Ai) / 1000.f;
B = ((float) Bi) / 100000.f;
L = ((float) Li) / 100.f;
R = ((float) Ri) / 100.f;
if (temporary) {
app_temp_set_calib_temporary(A, B);
app_temp_set_calib_temporary_r(L, R);
} else {
app_temp_set_calib_persistent(A, B);
app_temp_set_calib_persistent_r(L, R);
}
}

@ -0,0 +1,242 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stddef.h>
#include <string.h>
#include "app_gui.h"
#include "app_heater.h"
#include "screen_menu.h"
#include "ufb/fb_text.h"
#include "app_temp.h"
#include "snprintf.h"
#include "FreeRTOS.h"
struct calib_state {
int phase;
float sample1;
float sample2;
int temp1;
int temp2;
} s_calib;
enum Phase {
PH_HELLO = 0,
PH_SAMPLE1,
PH_TEMP1,
PH_SAMPLE2,
PH_TEMP2,
PH_DONE,
};
static void stop_heater() {
app_heater_set_target(0);
app_heater_enable(false);
}
static void calib_abort() {
app_temp_restore_calib();
stop_heater();
switch_screen(screen_home, true);
}
static void next_phase() {
PUTS("Phase++\r\n");
s_calib.phase++;
}
static const char* hello_menu_opts[] = {
"Pokračovat",
"Zrušit",
NULL
};
static void hello_menu_cb(int opt) {
switch (opt) {
case 0:
// Continue
next_phase();
request_paint();
app_heater_set_target(100);
app_heater_enable(true);
break;
case 1:
calib_abort();
break;
}
}
static const char* sample1_menu_opts[] = {
"Vzorek 1",
"Zrušit",
NULL
};
static void sample1_menu_cb(int opt) {
switch (opt) {
case 0:
// Continue
next_phase();
request_paint();
s_calib.temp1 = 100;
s_calib.sample1 = app_temp_read_oven_raw();
app_heater_enable(false);
break;
case 1:
calib_abort();
break;
}
}
static const char* sample2_menu_opts[] = {
"Vzorek 2",
"Zrušit",
NULL
};
static void sample2_menu_cb(int opt) {
switch (opt) {
case 0:
// Continue
next_phase();
request_paint();
s_calib.temp2 = 200;
s_calib.sample2 = app_temp_read_oven_raw();
app_heater_enable(false);
break;
case 1:
calib_abort();
break;
}
}
void screen_calibration(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
app_temp_backup_calib();
app_temp_set_calib_temporary(1, 0);
memset(&s_calib, 0, sizeof(s_calib));
// continue to the rest - so the menu can be inited
}
int *pT;
switch (s_calib.phase) {
case PH_HELLO:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 16, "Vychlaď", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "troubu", TEXT_CENTER, 1);
}
screen_menu_offset(event, hello_menu_opts, hello_menu_cb, 30);
break;
case PH_SAMPLE1:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 16, "Vyčkej", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "ustálení", TEXT_CENTER, 1);
}
screen_menu_offset(event, sample1_menu_opts, sample1_menu_cb, 30);
break;
case PH_SAMPLE2:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 16, "Vyčkej", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "ustálení", TEXT_CENTER, 1);
}
screen_menu_offset(event, sample2_menu_opts, sample2_menu_cb, 30);
break;
case PH_TEMP1:
case PH_TEMP2:
if (s_calib.phase == PH_TEMP1) {
pT = &s_calib.temp1;
} else {
pT = &s_calib.temp2;
}
if (push_time() > pdMS_TO_TICKS(500)) {
input_sound_effect();
calib_abort();
return;
}
switch (event) {
case GUI_EVENT_PAINT: {
fb_text(FBW/2, 14, s_calib.phase == PH_TEMP1 ? "Teplota 1" : "Teplota 2", TEXT_CENTER, 1);
SPRINTF(stmp, "%d°C", *pT);
fb_text(FBW/2, 30, stmp, TEXT_CENTER | FONT_DOUBLE, 1);
fb_text(2, FBH - 8 * 3, "←→Nastav", 0, 1);
fb_text(2, FBH - 8 * 2, "> Potvrdit", 0, 1);
fb_text(2, FBH - 8 * 1, "» Zrušit", 0, 1);
return;
}
case GUI_EVENT_KNOB_PLUS: {
if (*pT < 500) {
*pT += 1;
input_sound_effect();
request_paint();
}
break;
}
case GUI_EVENT_KNOB_MINUS: {
if (*pT > 0) {
input_sound_effect();
*pT -= 1;
request_paint();
}
break;
}
case GUI_EVENT_KNOB_RELEASE: {
next_phase();
request_paint();
PRINTF("KNOB_REL PH %d\r\n", s_calib.phase);
if (s_calib.phase == PH_DONE) {
app_heater_set_target(0);
app_heater_enable(false);
// TODO do the math
PRINTF("Sample 1 %f, T1 %d\r\n", s_calib.sample1, s_calib.temp1);
PRINTF("Sample 2 %f, T2 %d\r\n", s_calib.sample2, s_calib.temp2);
float corrected1 = c_to_val((float) s_calib.temp1);
float corrected2 = c_to_val((float) s_calib.temp2);
float a = (corrected1 - corrected2) / (s_calib.sample1 - s_calib.sample2);
float b = corrected1 - a * s_calib.sample1;
app_temp_set_calib_persistent(a, b);
} else if (s_calib.phase == PH_SAMPLE1) {
app_heater_set_target(100);
app_heater_enable(true);
} else if (s_calib.phase == PH_SAMPLE2) {
app_heater_set_target(200);
app_heater_enable(true);
}
break;
}
}
break;
case PH_DONE:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 14, "Hotovo", TEXT_CENTER, 1);
fb_text(FBW/2, 36, "→Hlavní menu", TEXT_CENTER, 1);
}
if (event == GUI_EVENT_KNOB_RELEASE) {
stop_heater();
switch_screen(screen_home, 1);
}
break;
}
}

@ -0,0 +1,44 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stddef.h>
#include <stdbool.h>
#include "app_gui.h"
#include "app_heater.h"
#include "screen_menu.h"
static const char* main_menu_opts[] = {
"Ruční režim",
"Ladění PID",
"Auto kalibrace",
"Ruční kalibrace",
NULL
};
static void main_menu_cb(int opt) {
switch (opt) {
case 0:
switch_screen(screen_manual, true);
break;
case 1:
switch_screen(screen_pid_tuning, true);
break;
case 2:
switch_screen(screen_calibration, true);
break;
case 3:
switch_screen(screen_calib_edit, true);
break;
}
}
void screen_home(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
app_heater_enable(false);
}
screen_menu(event, main_menu_opts, main_menu_cb);
}

@ -0,0 +1,78 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stddef.h>
#include <stdbool.h>
#include "app_gui.h"
#include "gui_event.h"
#include "screen_menu.h"
#include "app_heater.h"
#include "ufb/fb_7seg.h"
#include "FreeRTOS.h"
#include "ufb/fb_text.h"
void screen_manual(GuiEvent event)
{
bool temp_changed = false;
if (event == GUI_EVENT_SCREEN_INIT) {
app_heater_manual_override_clear();
app_heater_enable(false);
return;
}
// menu is activated by long push
if (push_time() >= pdMS_TO_TICKS(500)) {
switch_screen(screen_manual_menu, true);
return;
}
switch (event) {
case GUI_EVENT_PAINT:
fb_7seg_number(FBW/2 - ((12+2) * 3 - 2)/2, 36,
12, 20, 2, 2,
1,
s_app.set_temp, 3, 0
);
fb_text(FBW/2, 25, "Teplota °C", TEXT_CENTER, 1);
fb_text(FBW/2, 64, s_app.heater_enabled ? "ZAPNUTO" : "Vypnuto", TEXT_CENTER, 1);
SPRINTF(stmp, "%.1f", s_app.oven_temp);
fb_text(FBW/2, 80, stmp, TEXT_CENTER | FONT_DOUBLE, 1);
fb_text(2, FBH - 8 * 3, "←→Nastav", 0, 1);
fb_text(2, FBH - 8 * 2, "> Zap/Vyp", 0, 1);
fb_text(2, FBH - 8 * 1, "» Menu", 0, 1);
break;
case GUI_EVENT_KNOB_RELEASE:
input_sound_effect();
s_app.heater_enabled ^= 1;
app_heater_enable(s_app.heater_enabled);
request_paint();
break;
case GUI_EVENT_KNOB_PLUS:
if (s_app.set_temp <= MAX_TEMP - 5) {
s_app.set_temp += 5;
temp_changed = true;
}
break;
case GUI_EVENT_KNOB_MINUS:
if (s_app.set_temp >= 5) {
s_app.set_temp -= 5;
temp_changed = true;
}
break;
}
if (temp_changed) {
input_sound_effect();
app_heater_set_target((float) s_app.set_temp);
request_paint();
}
}

@ -0,0 +1,35 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stddef.h>
#include "app_gui.h"
#include "app_heater.h"
#include "screen_menu.h"
static const char* manual_menu_opts[] = {
"Zrušit",
"Hlavní menu",
NULL
};
static void manual_menu_cb(int opt) {
switch (opt) {
case 0:
// Close menu
switch_screen(screen_manual, false);
break;
case 1:
s_app.heater_enabled = false;
app_heater_enable(false);
switch_screen(screen_home, true);
break;
}
}
void screen_manual_menu(GuiEvent event)
{
screen_menu(event, manual_menu_opts, manual_menu_cb);
}

@ -0,0 +1,116 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <stdbool.h>
#include <string.h>
#include "screen_menu.h"
#include "app_gui.h"
#include "FreeRTOS.h"
#include "task.h"
#include "ufb/utf8.h"
#include "ufb/framebuffer_config.h"
#include "ufb/framebuffer.h"
#include "ufb/fb_text.h"
struct menu_state {
int pos;
int len;
uint32_t change_time;
uint32_t slide_end_time;
uint16_t text_slide;
void * last_opts;
} s_menu;
void screen_menu(GuiEvent event, const char **options, menu_callback_t cb) {
screen_menu_offset(event, options, cb, 15);
}
void screen_menu_offset(GuiEvent event, const char **options, menu_callback_t cb, fbpos_t offset) {
if (event != GUI_EVENT_SCREEN_INIT && s_menu.last_opts != (void*) options) {
// ensure the menu is properly inited when the options list changes.
screen_menu(GUI_EVENT_SCREEN_INIT, options, cb);
}
bool menu_changed = false;
const uint32_t tickNow = xTaskGetTickCount();
switch (event) {
case GUI_EVENT_SCREEN_INIT:
memset(&s_menu, 0, sizeof(s_menu));
s_menu.last_opts = (void*) options;
s_menu.change_time = tickNow;
// count options
const char **opt = options;
while (*opt) {
s_menu.len++;
opt++;
}
break;
case GUI_EVENT_SCREEN_TICK:
// long text sliding animation
if (tickNow - s_menu.change_time >= pdMS_TO_TICKS(500)) {
const uint32_t textlen = utf8_strlen(options[s_menu.pos]) * 6;
if (textlen >= FBW - 2) {
if (textlen - s_menu.text_slide > FBW - 1) {
s_menu.text_slide += 1;
if (textlen - s_menu.text_slide >= FBW - 1) {
s_menu.slide_end_time = tickNow;
}
} else if (tickNow - s_menu.slide_end_time >= pdMS_TO_TICKS(500)) {
s_menu.change_time = tickNow;
s_menu.slide_end_time = 0;
s_menu.text_slide = 0;
}
request_paint();
}
}
break;
case GUI_EVENT_PAINT:
for (int i = 0; i < s_menu.len; i++) {
// is the row currently rendered the selected row?
const bool is_selected = s_menu.pos == i;
const fbcolor_t color = !is_selected; // text color - black if selected, because it's inverted
const fbpos_t y = 12 + offset + i * 10 ;
fb_rect(0, y, FBW, 10, !color);
fb_text(1 - (is_selected ? s_menu.text_slide : 0), y + 1, options[i], FONT_5X7, color);
// ensure the text doesn't touch the edge (looks ugly)
fb_vline(FBW - 1, y, 10, !color);
fb_vline(0, y, 10, !color);
}
break;
// the button is held! release is what activates the button
case GUI_EVENT_KNOB_RELEASE:
input_sound_effect();
cb(s_menu.pos);
break;
case GUI_EVENT_KNOB_PLUS:
if (s_menu.pos < s_menu.len - 1) {
s_menu.pos++;
menu_changed = true;
}
break;
case GUI_EVENT_KNOB_MINUS:
if (s_menu.pos > 0) {
s_menu.pos--;
menu_changed = true;
}
break;
}
if (menu_changed) {
s_menu.change_time = tickNow;
s_menu.text_slide = 0;
s_menu.slide_end_time = 0;
input_sound_effect();
request_paint();
}
}

@ -0,0 +1,30 @@
//
// Created by MightyPork on 2023/04/09.
//
// Generic menu screen
//
#ifndef TOASTER_OVEN_BLUEPILL_SCREEN_MENU_H
#define TOASTER_OVEN_BLUEPILL_SCREEN_MENU_H
#include "gui_event.h"
#include "ufb/framebuffer.h"
/**
* Choice callback for the generic menu screen. Options are indexed from zero
*/
typedef void (*menu_callback_t)(int choice);
/**
* Generic menu screen (must be called from a screen function with the standard signature)
*
* @param event - currently handled event
* @param options - options for the menu (items to show, NULL terminated array of const strings)
* @param cb - choice callback
*/
void screen_menu(GuiEvent event, const char **options, menu_callback_t cb);
/** Menu with custom offset (default is 15) */
void screen_menu_offset(GuiEvent event, const char **options, menu_callback_t cb, fbpos_t offset);
#endif //TOASTER_OVEN_BLUEPILL_SCREEN_MENU_H

@ -0,0 +1,194 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <string.h>
#include "app_gui.h"
#include "app_heater.h"
#include "ufb/fb_text.h"
#include "snprintf.h"
static struct calib_tuning_state {
uint8_t digits[6 * 3];
// uint32_t Kp, Ki, Kd; // these are the float x 1000
int cursor; // the digit under cursor (range 0-17)
bool digit_editing; // true if we are editing a digit
} s_tuning;
static void draw_digit_row(int row) {
fbpos_t x = (FBW - (6 * 7 - 1)) / 2;
fbpos_t y = 30 + row * 10;
char buf2[2] = {};
int numofs = row * 6;
const char * labels[3] = {"P","I","D"};
fb_text(FBW - 4, y + 2, labels[row], FONT_3X5, 1);
bool significant = false;
for (int i = 0; i < 6; i++) {
if (i >= 2) significant = 1;
int val = s_tuning.digits[numofs + i];
if (val != 0) {
significant = true;
}
buf2[0] = '0' + val;
if (s_tuning.cursor == numofs + i) {
if (s_tuning.digit_editing) {
fb_rect(x-1, y-1, 5+2, 7+2, 1);
fb_text(x, y, buf2, 0, 0);
} else {
fb_hline(x, y + 8, 5, 1);
if (significant) fb_text(x, y, buf2, 0, 1);
}
} else {
if (significant) fb_text(x, y, buf2, 0, 1);
}
x += 6;
if ( i == 2) {
fb_text(x, y, ".", 0, 1);
x += 6;
}
}
}
void screen_pid_tuning(GuiEvent event)
{
float Kp;
float Ki;
float Kd;
uint32_t Kp_i;
uint32_t Ki_i;
uint32_t Kd_i;
if (event == GUI_EVENT_SCREEN_INIT) {
memset(&s_tuning, 0, sizeof(s_tuning));
app_heater_get_tuning(&Kp, &Ki, &Kd);
Kp_i = (uint32_t)(Kp * 1000.f);
Ki_i = (uint32_t)(Ki * 1000.f);
Kd_i = (uint32_t)(Kd * 1000.f);
char buf[19];
SNPRINTF(buf, 19, "%06lu%06lu%06lu", Kp_i, Ki_i, Kd_i);
for(int i = 0; i < 18; i++) {
s_tuning.digits[i] = buf[i] - '0';
}
}
switch (event) {
case GUI_EVENT_PAINT: {
fb_text(FBW / 2, 16, "Ladění PID", TEXT_CENTER, 1);
draw_digit_row(0);
draw_digit_row(1);
draw_digit_row(2);
if (s_tuning.cursor == 18) {
fb_rect(0, 68, FBW, 9, 1);
}
fb_text(FBW / 2, 69, "Zrušit", TEXT_CENTER, s_tuning.cursor != 18);
if (s_tuning.cursor == 19) {
fb_rect(0, 68 + 9, FBW, 9, 1);
}
fb_text(FBW / 2, 69 + 9, "Uložit", TEXT_CENTER, s_tuning.cursor != 19);
fb_text(2, FBH - 8 * (1 + (s_tuning.cursor < 18)), s_tuning.digit_editing ? "←→Hodnota" : "←→Kurzor", 0, 1);
if (s_tuning.cursor < 18) {
fb_text(2, FBH - 8 * 1, s_tuning.digit_editing ? "> Potvrdit" : "> Změnit", 0, 1);
}
return;
}
case GUI_EVENT_KNOB_PLUS: {
input_sound_effect();
request_paint();
if (s_tuning.digit_editing) {
if (s_tuning.digits[s_tuning.cursor] == 9) {
s_tuning.digits[s_tuning.cursor] = 0;
} else {
s_tuning.digits[s_tuning.cursor]++;
}
} else {
// 18 - cancel
// 19 - save
s_tuning.cursor++;
if (s_tuning.cursor > 17) {
s_tuning.digit_editing = false;
}
if (s_tuning.cursor > 19) {
s_tuning.cursor = 0;
}
}
break;
}
case GUI_EVENT_KNOB_MINUS: {
input_sound_effect();
request_paint();
if (s_tuning.digit_editing) {
if (s_tuning.digits[s_tuning.cursor] == 0) {
s_tuning.digits[s_tuning.cursor] = 9;
} else {
s_tuning.digits[s_tuning.cursor]--;
}
} else {
// 18 - cancel
// 19 - save
if (s_tuning.cursor == 0) {
s_tuning.cursor = 19;
s_tuning.digit_editing = false;
} else {
s_tuning.cursor--;
}
}
break;
}
case GUI_EVENT_KNOB_RELEASE: {
if (s_tuning.cursor < 18) {
s_tuning.digit_editing = !s_tuning.digit_editing;
} else if (s_tuning.cursor == 18) {
// cancel
switch_screen(screen_home, true);
} else if (s_tuning.cursor == 19) {
// save
Kp_i = Ki_i = Kd_i = 0;
for(int i = 0; i < 6; i++) {
Kp_i *= 10;
Kp_i += s_tuning.digits[i];
}
for(int i = 6; i < 12; i++) {
Ki_i *= 10;
Ki_i += s_tuning.digits[i];
}
for(int i = 12; i < 18; i++) {
Kd_i *= 10;
Kd_i += s_tuning.digits[i];
}
Kp = ((float) Kp_i) / 1000.f;
Ki = ((float) Ki_i) / 1000.f;
Kd = ((float) Kd_i) / 1000.f;
app_heater_set_tuning(Kp, Ki, Kd);
app_heater_save_tuning();
switch_screen(screen_home, true);
}
break;
}
}
}

@ -46,7 +46,7 @@ void MX_ADC1_Init(void)
PA0-WKUP ------> ADC1_IN0
PA1 ------> ADC1_IN1
*/
GPIO_InitStruct.Pin = ADC_PT100_Pin|ADC_SENSR_Pin;
GPIO_InitStruct.Pin = LL_GPIO_PIN_0|ADC_SENSR_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
@ -67,10 +67,6 @@ void MX_ADC1_Init(void)
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
/* ADC1 interrupt Init */
NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(ADC1_2_IRQn);
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
@ -82,10 +78,10 @@ void MX_ADC1_Init(void)
LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM1_CH1;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_4RANKS;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);

@ -19,8 +19,8 @@ void app_buzzer_init()
{
/* Enable buzzer PWM */
LL_TIM_OC_SetCompareCH1(TIM_BUZZER, 0);
LL_TIM_EnableCounter(TIM_BUZZER);
LL_TIM_CC_EnableChannel(TIM_BUZZER, LL_TIM_CHANNEL_CH1);
LL_TIM_EnableCounter(TIM_BUZZER);
// HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
// s_timer = xTimerCreate("beep", 50, 0, NULL, app_beep_end);

@ -1,14 +0,0 @@
/**
* TODO file description
*/
#include "app_gui.h"
#include "cmsis_os2.h"
#include "FreeRTOS.h"
#include "task.h"
void app_task_gui(void *argument) {
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

@ -1,10 +0,0 @@
/**
* TODO file description
*/
#ifndef BLUEPILLTROUBA_APP_GUI_H
#define BLUEPILLTROUBA_APP_GUI_H
void app_task_gui(void *argument);
#endif //BLUEPILLTROUBA_APP_GUI_H

@ -7,6 +7,12 @@
#include "app_heater.h"
#include "cmsis_os2.h"
#include "tim.h"
#include "queue.h"
#include "app_safety.h"
#include "Gui/gui_event.h"
#include "eeprom_emul.h"
#include "ee_addresses.h"
#include "transmute.h"
extern osMutexId_t heaterMutexHandle;
@ -36,12 +42,15 @@ static struct {
float tuning_p;
float tuning_i;
float tuning_d;
/// Manual PWM override (percent, -1 = override disable)
int manual_override;
// PID state
struct PID pid;
} state = {
.tuning_p = 10.0f,
.tuning_i = 0.052f,
.tuning_d = 100.0f,
.manual_override = -1,
.pid = {
.SampleTimeTicks = pdMS_TO_TICKS(1000),
.outMax = 100.0f,
@ -59,33 +68,132 @@ static inline void heaterExitCritical() {
osMutexRelease(heaterMutexHandle);
}
void app_heater_manual_override(int percent) {
PRINTF("Set manual override: %d\r\n", percent);
heaterEnterCritical();
PID_SetCtlMode(&state.pid, PID_MANUAL);
state.manual_override = percent;
heaterExitCritical();
}
void app_heater_manual_override_clear() {
app_heater_manual_override(-1);
}
void app_heater_set_tuning(float p, float i, float d) {
heaterEnterCritical();
state.tuning_p = p;
state.tuning_i = i;
state.tuning_d = d;
PID_SetTunings(&state.pid, p, i, d);
heaterExitCritical();
}
void app_heater_get_tuning(float *p, float *i, float *d) {
if (!p || !i || !d) return; // fail
*p = state.tuning_p;
*i = state.tuning_i;
*d = state.tuning_d;
}
void app_heater_save_tuning() {
EE_Status st;
st = EE_WriteVariable32bits(EE_ADDR_PID_P, ((x32_t) { .f = state.tuning_p }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
st = EE_WriteVariable32bits(EE_ADDR_PID_I, ((x32_t) { .f = state.tuning_i }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
st = EE_WriteVariable32bits(EE_ADDR_PID_D, ((x32_t) { .f = state.tuning_d }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
}
void app_heater_enable(bool enable) {
printf("Set heater enabled = %d\r\n", (int) enable);
PRINTF("Set heater enabled = %d\r\n", (int) enable);
heaterEnterCritical();
PID_SetCtlMode(&state.pid, enable ? PID_AUTOMATIC : PID_MANUAL);
heaterExitCritical();
}
void app_heater_set_target(float target) {
printf("Set heater target = %d\r\n", (int) target);
PRINTF("Set heater target = %d\r\n", (int) target);
heaterEnterCritical();
PID_SetSetpoint(&state.pid, target);
heaterExitCritical();
}
bool app_heater_get_state() {
return state.pid.ctlMode == PID_AUTOMATIC;
}
float app_heater_get_percent() {
return state.pid.Output;
}
float app_heater_get_target() {
return state.pid.Setpoint;
}
// emergency shutdown, this must not block use RTOS since it can be called from fault handlers or interrupt
void app_heater_emergency_shutdown() {
// Stop pwm
LL_TIM_OC_SetCompareCH1(TIM_HEATER, 0);
LL_TIM_CC_DisableChannel(TIM_HEATER, LL_TIM_CHANNEL_CH1);
LL_TIM_DisableCounter(TIM_HEATER);
// Also kill the GPIO PWM output
LL_GPIO_InitTypeDef GPIO_InitStruct = {};
GPIO_InitStruct.Pin = PWM_HEATER_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
LL_GPIO_Init(PWM_HEATER_GPIO_Port, &GPIO_InitStruct);
// Output zero
LL_GPIO_ResetOutputPin(PWM_HEATER_GPIO_Port, PWM_HEATER_Pin);
}
void app_task_heater(void *argument)
{
// Wait until inited
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
PUTS("Heater task starts\r\n");
uint32_t c = 0;
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_P, &c)) {
state.tuning_p = ((x32_t) { .u = c }).f;
PRINTF("Loaded Kp = %f\r\n", state.tuning_p);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_I, &c)) {
state.tuning_i = ((x32_t) { .u = c }).f;
PRINTF("Loaded Ki = %f\r\n", state.tuning_i);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_D, &c)) {
state.tuning_d = ((x32_t) { .u = c }).f;
PRINTF("Loaded Kd = %f\r\n", state.tuning_d);
}
heater_pwm_init();
heaterEnterCritical();
// TODO load from flash
PID_SetTunings(&state.pid, state.tuning_p, state.tuning_i, state.tuning_d);
PID_SetOutputLimits(&state.pid, 0, 100);
PID_SetITermLimits(&state.pid, 0, 100);
PID_Initialize(&state.pid);
heaterExitCritical();
@ -96,19 +204,29 @@ void app_task_heater(void *argument)
state.oven_temp = app_temp_read_oven();
state.soc_temp = app_temp_read_soc();
enum GuiEvent ev = GUI_EVENT_TEMP_CHANGE;
xQueueSend(guiEventQueHandle, &ev, pdMS_TO_TICKS(100));
heaterEnterCritical();
PID_Compute(&state.pid, state.oven_temp);
if (state.pid.ctlMode == PID_AUTOMATIC) {
printf("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output);
heater_pwm_set_perc(state.pid.Output);
app_safety_pass_reg_loop_running();
if (state.manual_override >= 0 && state.manual_override <= 100) {
PRINTF("manual override %d%%\r\n", state.manual_override);
heater_pwm_set_perc(state.manual_override);
} else {
// turn it off
heater_pwm_set_perc(0);
PID_Compute(&state.pid, state.oven_temp);
if (state.pid.ctlMode == PID_AUTOMATIC) {
PRINTF("temp %d, output %d\r\n", (int) state.oven_temp, (int) state.pid.Output);
heater_pwm_set_perc(state.pid.Output);
} else {
// turn it off
heater_pwm_set_perc(0);
}
}
heaterExitCritical();
// TODO notify UI thread of the new temperature and heating percent
vTaskDelayUntil(&wake_time, pdMS_TO_TICKS(500));
vTaskDelayUntil(&wake_time, pdMS_TO_TICKS(100));
}
}

@ -6,13 +6,31 @@
#define BLUEPILLTROUBA_APP_HEATER_H
#include <stdbool.h>
#include "cmsis_os2.h"
#define MAX_TEMP 400
extern osThreadId_t heaterTskHandle;
void app_task_heater(void *argument);
/// Clear manual override, disable heater for normal mode.
void app_heater_manual_override_clear();
/// Set manual override PWM 0-100%.
/// Also disables heater in the normal mode.
void app_heater_manual_override(int percent);
/// Set heater regulator tuning.
/// Mutex is locked internally.
void app_heater_set_tuning(float p, float i, float d);
/// Get current tuning, passed out via pointers in arguments
void app_heater_get_tuning(float *p, float *i, float *d);
/// Save current tuning to EE
void app_heater_save_tuning();
/// Set heater on/off.
/// Mutex is locked internally.
void app_heater_enable(bool enable);
@ -21,4 +39,14 @@ void app_heater_enable(bool enable);
/// Mutex is locked internally.
void app_heater_set_target(float target);
/// Shutdown the heater; This function does not use mutex and just disables the PWM via register access.
void app_heater_emergency_shutdown();
bool app_heater_get_state();
float app_heater_get_target();
float app_heater_get_percent();
#endif //BLUEPILLTROUBA_APP_HEATER_H

@ -6,6 +6,14 @@
#include "main.h"
#include "app_knob.h"
#include "tim.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "timers.h"
#include "cmsis_os2.h"
#include "Gui/gui_event.h"
extern osTimerId_t buttonPushTimerHandle;
extern osTimerId_t buttonReleaseTimerHandle;
static struct {
uint16_t wheel;
@ -18,14 +26,68 @@ void app_knob_init()
LL_TIM_CC_EnableChannel(TIM_KNOB, LL_TIM_CHANNEL_CH1 | LL_TIM_CHANNEL_CH2);
LL_TIM_EnableCounter(TIM_KNOB);
// HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);
// for the change interrupt
LL_TIM_EnableIT_CC1(TIM_KNOB);
LL_TIM_EnableIT_CC2(TIM_KNOB);
}
uint16_t app_knob_get_raw() {
return LL_TIM_GetCounter(TIM_KNOB);
}
static char buf[100];
void app_knob_turn_isr()
{
// TODO
uint16_t old_wheel = s_knob.wheel;
s_knob.wheel = LL_TIM_GetCounter(TIM_KNOB);
int16_t wheel_change = (int16_t)(s_knob.wheel - old_wheel);
BaseType_t yield = pdFALSE;
while (wheel_change > 0) {
wheel_change--;
enum GuiEvent ev = GUI_EVENT_KNOB_PLUS;
xQueueSendFromISR(guiEventQueHandle, &ev, &yield);
}
while (wheel_change < 0) {
wheel_change++;
enum GuiEvent ev = GUI_EVENT_KNOB_MINUS;
xQueueSendFromISR(guiEventQueHandle, &ev, &yield);
}
portYIELD_FROM_ISR(yield);
}
// TODO use EXTI for push
bool app_knob_pushed() {
return 0 == LL_GPIO_IsInputPinSet(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
}
void app_knob_push_isr(bool push)
{
//PUTCHAR(push ? '#' : '.');
BaseType_t yield = pdFALSE;
if (push) {
xTimerStopFromISR(buttonReleaseTimerHandle, &yield);
xTimerStopFromISR(buttonPushTimerHandle, &yield);
xTimerChangePeriodFromISR(buttonPushTimerHandle, pdMS_TO_TICKS(10), &yield);
} else {
xTimerStopFromISR(buttonPushTimerHandle, &yield);
xTimerStopFromISR(buttonReleaseTimerHandle, &yield);
xTimerChangePeriodFromISR(buttonReleaseTimerHandle, pdMS_TO_TICKS(10), &yield);
}
portYIELD_FROM_ISR(yield);
}
void app_push_debounce(void *argument) {
bool push = (bool) argument;
enum GuiEvent ev = push ? GUI_EVENT_KNOB_PRESS : GUI_EVENT_KNOB_RELEASE;
xQueueSend(guiEventQueHandle, &ev, pdMS_TO_TICKS(100));
}

@ -5,9 +5,14 @@
#ifndef BLUEPILLTROUBA_APP_KNOB_H
#define BLUEPILLTROUBA_APP_KNOB_H
#include <stdbool.h>
void app_knob_init();
uint16_t app_knob_get_raw();
bool app_knob_pushed();
void app_knob_turn_isr();
void app_knob_push_isr(bool push);
#endif //BLUEPILLTROUBA_APP_KNOB_H

@ -12,78 +12,88 @@
#include "ufb/framebuffer.h"
#include "iwdg.h"
#include "app_oled.h"
#include "ufb/fb_text.h"
#include "ufb/fb_7seg.h"
//#include "ufb/fb_text.h"
//#include "ufb/fb_7seg.h"
#include "app_temp.h"
#include "app_knob.h"
#include "app_buzzer.h"
#include "app_heater.h"
//#include "app_heater.h"
//#include "cmsis_os2.h"
#include "eeprom_emul.h"
#include "app_safety.h"
#include "cmsis_os2.h"
static struct App {
float oven_temp;
int16_t set_temp;
int16_t wheel_normed;
uint16_t wheel;
bool run;
} s_app = {};
static void redraw_display() {
fb_clear();
char tmp[100];
sprintf(tmp, "T=%d°C", (int) s_app.oven_temp);
fb_text(3, 3, tmp, FONT_5X7, 1);
sprintf(tmp, "Cil=%d°C", s_app.set_temp);
fb_text(3, 11, tmp, FONT_5X7, 1);
sprintf(tmp, "Stav=%s", s_app.run ? "ZAP" : "VYP");
fb_text(3, 19, tmp, FONT_5X7, 1);
if (s_app.run) {
fb_frame(0, 0, FBW, FBH, 2, 1);
}
// some funny effects to showcase responsiveness and circle drawing
fb_circle(FBW / 2, 70, 18, 1, 1);
for (int i = 0; i < 6; i++) {
float x = FBW / 2;
float y = 70;
int ii = i;
float angle = (float) ii * (M_PI / 3.0) - s_app.wheel_normed * (M_PI / 24);
x = x + sinf(angle) * 10;
y = y + cosf(angle) * 10;
fb_circle((fbpos_t) x, (fbpos_t) y, 4, i==0?4:1, 1);
}
fb_text(0, s_app.wheel_normed, ":3 :3", FONT_4X5, 1);
fb_7seg_number(
2, FBH - 20,
10, 16,
2, // th
2, // spacing
1, // color
s_app.wheel,
4, // places
2);// decimals
fb_blit();
}
extern osThreadId_t heaterTskHandle;
extern osThreadId_t mainTskHandle;
extern osThreadId_t guiTskHandle;
//static struct App {
// float oven_temp;
// int16_t set_temp;
// int16_t wheel_normed;
// uint16_t wheel;
// bool run;
//} s_app = {};
//static void redraw_display() {
// fb_clear();
//
// char tmp[100];
//
// SPRINTF(tmp, "T=%d°C", (int) s_app.oven_temp);
// fb_text(3, 3, tmp, FONT_5X7, 1);
//
// SPRINTF(tmp, "Cil=%d°C", s_app.set_temp);
// fb_text(3, 11, tmp, FONT_5X7, 1);
//
// SPRINTF(tmp, "Stav=%s", s_app.run ? "ZAP" : "VYP");
// fb_text(3, 19, tmp, FONT_5X7, 1);
//
// if (s_app.run) {
// fb_frame(0, 0, FBW, FBH, 2, 1);
// }
//
// // some funny effects to showcase responsiveness and circle drawing
//
// fb_circle(FBW / 2, 70, 18, 1, 1);
//
// for (int i = 0; i < 6; i++) {
// float x = FBW / 2;
// float y = 70;
//
// int ii = i;
//
// float angle = (float) ii * (M_PI / 3.0) - s_app.wheel_normed * (M_PI / 24);
//
// x = x + sinf(angle) * 10;
// y = y + cosf(angle) * 10;
//
// fb_circle((fbpos_t) x, (fbpos_t) y, 4, i==0?4:1, 1);
// }
//
// fb_text(0, s_app.wheel_normed, ":3 :3", FONT_4X5, 1);
//
// fb_7seg_number(
// 2, FBH - 20,
// 10, 16,
// 2, // th
// 2, // spacing
// 1, // color
// s_app.wheel,
// 4, // places
// 2);// decimals
//
//
//
// fb_blit();
//}
void app_task_main(void *argument)
{
printf("Main task\r\n");
PUTS("Main task\r\n");
EE_Init(EE_CONDITIONAL_ERASE);
app_analog_init();
app_buzzer_init();
app_knob_init();
@ -92,66 +102,78 @@ void app_task_main(void *argument)
oled_init();
fb_clear();
/* Infinite loop */
bool old_pushed = app_knob_pushed();
bool any_change = true;
uint32_t last_redraw = osKernelGetTickCount();
printf("Loop\r\n");
for (;;) {
// sampling is done in the heater loop
s_app.oven_temp = app_temp_read_oven();
uint16_t old_wheel = s_app.wheel;
s_app.wheel = app_knob_get_raw();
// TODO do this with interrupt and/or debouncing
bool pushed = app_knob_pushed();
if (pushed && !old_pushed) {
s_app.run ^= 1;
app_heater_enable(s_app.run);
app_buzzer_beep();
any_change = true;
}
old_pushed = pushed;
/* all inited */
int16_t wheel_change = (int16_t)(s_app.wheel - old_wheel);
if (wheel_change != 0) {
s_app.wheel_normed += wheel_change;
if (s_app.wheel_normed < 0) {
s_app.wheel_normed = 0;
}
if (s_app.wheel_normed > 500) {
s_app.wheel_normed = 500;
}
// notify threads that we are ready
xTaskNotifyGive(guiTskHandle);
xTaskNotifyGive(heaterTskHandle);
int16_t old_temp = s_app.set_temp;
// while(1) {
// LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
// vTaskDelay(pdMS_TO_TICKS(250));
// LL_IWDG_ReloadCounter(IWDG);
// }
s_app.set_temp = (s_app.wheel_normed / 2) * 5;
// /* Infinite loop */
// bool old_pushed = app_knob_pushed();
//
// bool any_change = true;
// uint32_t last_redraw = osKernelGetTickCount();
if (old_temp != s_app.set_temp) {
app_buzzer_beep();
app_heater_set_target((float) s_app.set_temp);
any_change = true;
}
}
uint32_t now = osKernelGetTickCount();
if (any_change || (now - last_redraw > pdMS_TO_TICKS(500))) {
last_redraw = now;
redraw_display();
any_change = false;
// Blink
LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
PUTS("Main loop\r\n");
for (;;) {
// sampling is done in the heater loop
vTaskDelay(pdMS_TO_TICKS(10));
// s_app.oven_temp = app_temp_read_oven();
//
// uint16_t old_wheel = s_app.wheel;
// s_app.wheel = app_knob_get_raw();
//
// // TODO do this with interrupt and/or debouncing
// bool pushed = app_knob_pushed();
// if (pushed && !old_pushed) {
// s_app.run ^= 1;
// app_heater_enable(s_app.run);
// app_buzzer_beep();
// any_change = true;
// }
// old_pushed = pushed;
//
//
// int16_t wheel_change = (int16_t)(s_app.wheel - old_wheel);
// if (wheel_change != 0) {
// s_app.wheel_normed += wheel_change;
// if (s_app.wheel_normed < 0) {
// s_app.wheel_normed = 0;
// }
// if (s_app.wheel_normed > 500) {
// s_app.wheel_normed = 500;
// }
//
// int16_t old_temp = s_app.set_temp;
//
// s_app.set_temp = (s_app.wheel_normed / 2) * 5;
//
// if (old_temp != s_app.set_temp) {
// app_buzzer_beep();
// app_heater_set_target((float) s_app.set_temp);
// any_change = true;
// }
// }
//
// uint32_t now = osKernelGetTickCount();
// if (any_change || (now - last_redraw > pdMS_TO_TICKS(500))) {
// last_redraw = now;
// redraw_display();
// any_change = false;
//
// // Blink
//
// }
vTaskDelay(pdMS_TO_TICKS(100));
// feed dogs
LL_IWDG_ReloadCounter(IWDG);
app_safety_poll();
}
}

@ -2,13 +2,8 @@
// Created by MightyPork on 2022/12/28.
//
#include <stdio.h>
#include <string.h>
#include "ufb/framebuffer.h"
#include "gpio.h"
#include "spi.h"
#include "FreeRTOS.h"
#define SSD1309_HEIGHT 64

@ -13,8 +13,8 @@ static void clampOutput(struct PID *self)
static void clampIterm(struct PID *self)
{
if (self->ITerm > self->outMax) { self->ITerm = self->outMax; }
else if (self->ITerm < self->outMin) { self->ITerm = self->outMin; }
if (self->ITerm > self->iTermMax) { self->ITerm = self->iTermMax; }
else if (self->ITerm < self->iTermMin) { self->ITerm = self->iTermMin; }
}
void PID_Compute(struct PID *self, float input)
@ -25,17 +25,22 @@ void PID_Compute(struct PID *self, float input)
uint32_t now = xTaskGetTickCount();
int32_t timeChange = (now - self->lastTime);
if (timeChange >= self->SampleTimeTicks) {
printf("compute\r\n");
PUTS("compute\r\n");
/*Compute all the working error variables*/
float error = self->Setpoint - input;
self->ITerm += (self->ki * error);
clampIterm(self);
// Shortcut to reduce overshoot
if (error < 0 && self->ITerm > 0) {
self->ITerm = 0;
}
float dInput = (input - self->lastInput);
printf("calc x100 %d + %d - %d\r\n",
PRINTF("calc x100 %d + %d - %d\r\n",
(int) (100 * (self->kp * error)),
(int) (100 * (self->ITerm)),
(int) (100 * (self->kd * dInput))
@ -91,6 +96,14 @@ void PID_SetOutputLimits(struct PID *self, float min, float max)
self->outMax = max;
clampOutput(self);
}
void PID_SetITermLimits(struct PID *self, float min, float max)
{
if (min > max) { return; }
self->iTermMin = min;
self->iTermMax = max;
clampIterm(self);
}

@ -27,6 +27,7 @@ struct PID {
float kp, ki, kd;
uint32_t SampleTimeTicks;
float outMin, outMax;
float iTermMin, iTermMax;
enum PIDCtlMode ctlMode; // false
enum PIDDirection controllerDirection;
};
@ -41,6 +42,8 @@ void PID_SetSampleTime(struct PID *self, uint32_t new_sample_time);
void PID_SetOutputLimits(struct PID *self, float min, float max);
void PID_SetITermLimits(struct PID *self, float min, float max);
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode mode);
void PID_Initialize(struct PID *self);

@ -0,0 +1,66 @@
/**
* TODO file description
*/
#include "app_safety.h"
#include "app_heater.h"
#include "snprintf.h"
#include "stm32f1xx_ll_iwdg.h"
#include "stm32f1xx_ll_gpio.h"
#include "main.h"
#define HB_FLAG_TEMP_NORMAL (1 << 0)
#define HB_FLAG_ADC_SAMPLING (1 << 1)
#define HB_FLAG_TEMP_CALCULATION (1 << 2)
#define HB_FLAG_REG_LOOP (1 << 3)
#define HB_FLAG_DISPLAY_UPDATING (1 << 4)
#define HB_FLAG_SOC_TEMP_OK (1 << 5)
//#define HB_FLAG_ALL (0b111111)
#define HB_FLAG_ALL (0b111110) // FIXME !!!! disabling the temp watchdog
static volatile uint32_t heartbeat_flags = 0;
void app_safety_pass_temp_normal() {
heartbeat_flags |= HB_FLAG_TEMP_NORMAL;
}
void app_safety_pass_adc_sampling() {
heartbeat_flags |= HB_FLAG_ADC_SAMPLING;
}
void app_safety_pass_temp_calculation() {
heartbeat_flags |= HB_FLAG_TEMP_CALCULATION;
}
void app_safety_pass_reg_loop_running() {
heartbeat_flags |= HB_FLAG_REG_LOOP;
}
void app_safety_pass_display_updating() {
heartbeat_flags |= HB_FLAG_DISPLAY_UPDATING;
}
void app_safety_pass_soc_temp_ok() {
heartbeat_flags |= HB_FLAG_SOC_TEMP_OK;
}
void app_safety_poll() {
//PRINTF("\r\n*** HB FLAGS %x ***\r\n", heartbeat_flags);
if ((heartbeat_flags & HB_FLAG_ALL) == HB_FLAG_ALL) {
LL_IWDG_ReloadCounter(IWDG);
LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
heartbeat_flags = 0;
}
}
// emergency shutdown, this must not block use RTOS since it can be called from fault handlers or interrupt
void __attribute__((noreturn)) app_emergency_stop() {
app_heater_emergency_shutdown();
PUTS("\r\n*** EMERGENCY STOP ***\r\n");
while (1) {
// wait for the watchdog to bite
}
}

@ -0,0 +1,30 @@
/**
* TODO file description
*/
#ifndef BLUEPILLTROUBA_APP_SAFETY_H
#define BLUEPILLTROUBA_APP_SAFETY_H
/**
* Check the pass flags. If all are set, reset the WD and clear flags.
*
* This effectively makes the WD bite when either of the subsystems fails.
*/
void app_safety_poll();
void app_emergency_stop()
__attribute__((noreturn));
void app_safety_pass_temp_normal();
void app_safety_pass_adc_sampling();
void app_safety_pass_temp_calculation();
void app_safety_pass_reg_loop_running();
void app_safety_pass_display_updating();
void app_safety_pass_soc_temp_ok();
#endif //BLUEPILLTROUBA_APP_SAFETY_H

@ -3,142 +3,374 @@
*/
#include "main.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "app_temp.h"
#include "adc.h"
#include "snprintf.h"
#include "app_safety.h"
#include "eeprom_emul_types.h"
#include "eeprom_emul.h"
#include "ee_addresses.h"
#include "transmute.h"
/* DMA dest */
static volatile uint16_t adc_values[4];
const float V_REFINT = 1.23f;
#define AVERAGEBUF_DEPTH 16
#define OVENTEMP_HISTORY_DEPTH 10
#define AVERAGEBUF_DEPTH 4
#define OVENTEMP_HISTORY_DEPTH 4
static struct App {
float oven_temp;
float oven_temp_raw;
float soc_temp;
float v_sensor;
float cal_a;
float cal_b;
float reference_resistor;
float lead_resistance;
// original values are copied here during calibration, so they can be reverted
float saved_cal_a;
float saved_cal_b;
float saved_lead_resistance;
float saved_reference_resistor;
float oventemp_history[OVENTEMP_HISTORY_DEPTH]; // raw temp
uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4];
uint8_t averagebuf_ptr;
float adc_averages[4];
float oventemp_history[OVENTEMP_HISTORY_DEPTH];
uint8_t oventemp_history_ptr;
} s_analog = {};
} s_analog = {
.reference_resistor = 1000.0f,
.lead_resistance = 0.0f,
// Ax + B = y ... X = raw sample (ratio 0-1 of 3.3), Y = corrected sample
.cal_a = 1.0f, // safe default calibration constants
.cal_b = 0.0f,
};
#define TSENSE_LOOKUP_LEN 101
#define TSENSE_T_STEP 5.0f
#define TSENSE_T_MIN 0.0f
#define TSENSE_T_MAX 500.0f
#if 0 // Ratios
static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
0.092678405931418f,
0.0943174479327356f,
0.095948157844312f,
0.0975706768542549f,
0.0991848957506647f,
0.100791037522732f,
0.102388993070241f,
0.103978983136042f,
0.105560980458654f,
0.107135039851509f,
0.108701215616829f,
0.110259642413441f,
0.111810211533421f,
0.113353137226489f,
0.114888310929339f,
0.11641594480226f,
0.117936009906507f,
0.119448557132363f,
0.120953636903929f,
0.122451377845456f,
0.12394167187544f,
0.125424725109556f,
0.126900429638119f,
0.128368989630084f,
0.129830374697352f,
0.131284632150064f,
0.132731808872517f,
0.134172027901771f,
0.135605181883591f,
0.13703146935069f,
0.138450783142958f,
0.139863319976468f,
0.14126904821384f,
0.142668011892657f,
0.144060254660872f,
0.145445894373796f,
0.146824824486877f,
0.14819723645253f,
0.149563023938454f,
0.150922376699229f,
0.15227526202401f,
0.153621720954182f,
0.15496179417407f,
0.156295594725426f,
0.157623016940038f,
0.158944245649448f,
0.160259175412251f,
0.16156798947087f,
0.162870654195634f,
0.164167207880495f,
0.165457688491696f,
0.166742204592451f,
0.168020651444079f,
0.169293207677971f,
0.170559768793747f,
0.171820511933356f,
0.173075402684405f,
0.174324476817747f,
0.175567769803026f,
0.176805386030345f,
0.178037221732226f,
0.179263449725904f,
0.180483966491086f,
0.181698943447122f,
0.182908345518766f,
0.184112206156428f,
0.185310558533273f,
0.186503503145257f,
0.187690937227925f,
0.188873028139146f,
0.190049673368296f,
0.191221038959601f,
0.192387089280576f,
0.193547855644572f,
0.194703369109397f,
0.195853726532112f,
0.196998826174689f,
0.19813883026229f,
0.199273637315452f,
0.200403408323351f,
0.201528107189346f,
0.20264776325594f,
0.203762405629782f,
0.204872127762998f,
0.205976828960191f,
0.207076666615101f,
0.208171540293999f,
0.209261606226334f,
0.210346827933364f,
0.211427232937629f,
0.212502848543705f,
0.213573765013592f,
0.214639882704581f,
0.215701354457324f,
0.216758080892489f,
0.217810213752734f,
0.218857716249547f,
0.219900614222686f,
0.220938933310224f,
0.221972760781578f,
0.223001998051553f,
0.0909090909090909f,
0.0925200328471449f,
0.0941228958173389f,
0.0957178169362106f,
0.0973046872002769f,
0.0988837241910161f,
0.100454819038946f,
0.102018187184848f,
0.103573800259031f,
0.105121710606384f,
0.106661970090864f,
0.108194709632656f,
0.109719820815089f,
0.111237512887056f,
0.112747677594865f,
0.114250522193605f,
0.115746016789507f,
0.117234210034522f,
0.118715150141415f,
0.120188962295434f,
0.121655538774297f,
0.123115081061434f,
0.124567481621389f,
0.126012940077612f,
0.127451425220842f,
0.128882982328346f,
0.13030765627567f,
0.131725566931108f,
0.133136607355006f,
0.134540971782401f,
0.135938553479917f,
0.137329544944786f,
0.138713913835562f,
0.140091702340679f,
0.141462952280536f,
0.142827778585901f,
0.144186075171443f,
0.145538029496198f,
0.146883535696824f,
0.148222779606307f,
0.149555727912261f,
0.150882419971517f,
0.152202894803216f,
0.153517262745702f,
0.154825418625535f,
0.156127543558165f,
0.157423532604634f,
0.158713565356767f,
0.159997607673187f,
0.161275696311014f,
0.162547867717066f,
0.163814227951767f,
0.165074672799026f,
0.166329377427284f,
0.167578237864685f,
0.168821427850084f,
0.170058912538152f,
0.171290726295724f,
0.172516903204089f,
0.17373754533289f,
0.174952549458501f,
0.176162085166716f,
0.177366049485545f,
0.178564610657697f,
0.179757733244091f,
0.180945449410727f,
0.182127791060477f,
0.183304856534839f,
0.184476543628915f,
0.185643016681207f,
0.186804173743842f,
0.18796017789194f,
0.18911099318983f,
0.190256649774341f,
0.191397177539504f,
0.192532671339319f,
0.193663030006298f,
0.194788412940845f,
0.195908719236171f,
0.197024107102852f,
0.198134540194308f,
0.19924004677399f,
0.200340654881021f,
0.201436456102762f,
0.202527350321362f,
0.203613492284647f,
0.204694782137667f,
0.205771373506423f,
0.206843229708988f,
0.20791037727704f,
0.208972842534733f,
0.210030714005839f,
0.211083892628833f,
0.212132528763072f,
0.213176523610881f,
0.214216026472748f,
0.215251000398025f,
0.216281470315524f,
0.21730746096184f,
0.218329057984116f,
0.219346163379138f,
};
#else
static const float PT100_LOOKUP[TSENSE_LOOKUP_LEN] = {
100.f, // 0 C
101.9527f,
103.9025f,
105.8495f,
107.7935f,
109.7347f,
111.6729f,
113.6083f,
115.5408f,
117.4704f,
119.3971f,
121.321f,
123.2419f,
125.16f,
127.0751f,
128.9874f,
130.8968f,
132.8033f,
134.7069f,
136.6077f,
138.5055f,
140.4005f,
142.2925f,
144.1817f,
146.068f,
147.9514f,
149.8319f,
151.7096f,
153.5843f,
155.4562f,
157.3251f,
159.1912f,
161.0544f,
162.9147f,
164.7721f,
166.6267f,
168.4783f,
170.3271f,
172.1729f,
174.0159f,
175.856f,
177.6932f,
179.5275f,
181.359f,
183.1875f,
185.0132f,
186.8359f,
188.6558f,
190.4728f,
192.2869f,
194.0981f,
195.9065f,
197.7119f,
199.5145f,
201.3141f,
203.1109f,
204.9048f,
206.6958f,
208.4839f,
210.2692f,
212.0515f,
213.831f,
215.6075f,
217.3812f,
219.152f,
220.9199f,
222.6849f,
224.4471f,
226.2063f,
227.9627f,
229.7161f,
231.4667f,
233.2144f,
234.9592f,
236.7011f,
238.4402f,
240.1763f,
241.9096f,
243.6399f,
245.3674f,
247.092f,
248.8137f,
250.5325f,
252.2485f,
253.9615f,
255.6717f,
257.3789f,
259.0833f,
260.7848f,
262.4834f,
264.1791f,
265.872f,
267.5619f,
269.249f,
270.9331f,
272.6144f,
274.2928f,
275.9683f,
277.6409f,
279.3107f,
280.9775f, // 500 C
};
#endif
void app_temp_get_calib(float *a, float *b, float *l, float *r) {
*a = s_analog.cal_a;
*b = s_analog.cal_b;
*l = s_analog.lead_resistance;
*r = s_analog.reference_resistor;
}
/// if the calibration constants are zero, reset to defaults
static void correct_invalid_calib() {
if (s_analog.cal_a == 0.0f) { // || s_analog.cal_b == 0.0f
PRINTF("ADC invalid calib, reset\r\n");
s_analog.cal_a = 1.0f;
}
if (s_analog.reference_resistor == 0.0f) {
s_analog.reference_resistor = 1000.0f;
}
// 0 lead_r is a lie, but ok
// if (s_analog.lead_resistance == 0.0f) {
// s_analog.lead_resistance = 0.0f;
// }
}
/// Set and persist calibration constants
void app_temp_set_calib_persistent(float a, float b) {
s_analog.cal_a = a;
s_analog.cal_b = b;
correct_invalid_calib();
EE_Status st = EE_WriteVariable32bits(EE_ADDR_CAL_A, ((x32_t) { .f = a }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
st = EE_WriteVariable32bits(EE_ADDR_CAL_B, ((x32_t) { .f = b }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
}
void app_temp_set_calib_persistent_r(float lead, float reference) {
s_analog.lead_resistance = lead;
s_analog.reference_resistor = reference;
correct_invalid_calib();
EE_Status st = EE_WriteVariable32bits(EE_ADDR_LEAD_R, ((x32_t) { .f = lead }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
st = EE_WriteVariable32bits(EE_ADDR_REF_R, ((x32_t) { .f = reference }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
}
void app_temp_backup_calib() {
s_analog.saved_cal_a = s_analog.cal_a;
s_analog.saved_cal_b = s_analog.cal_b;
s_analog.saved_lead_resistance = s_analog.lead_resistance;
s_analog.saved_reference_resistor = s_analog.reference_resistor;
}
void app_temp_set_calib_temporary(float a, float b) {
s_analog.cal_a = a;
s_analog.cal_b = b;
}
void app_temp_set_calib_temporary_r(float l, float r) {
s_analog.lead_resistance = l;
s_analog.reference_resistor = r;
}
void app_temp_restore_calib() {
s_analog.cal_a = s_analog.saved_cal_a;
s_analog.cal_b = s_analog.saved_cal_b;
s_analog.lead_resistance = s_analog.saved_lead_resistance;
s_analog.reference_resistor = s_analog.saved_reference_resistor;
}
void app_analog_init()
{
// read calibration constants
uint32_t c = 0;
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_CAL_A, &c)) {
s_analog.cal_a = ((x32_t) { .u = c }).f;
PRINTF("ADC calib a read from EE: %f\r\n", s_analog.cal_a);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_CAL_B, &c)) {
s_analog.cal_b = ((x32_t) { .u = c }).f;
PRINTF("ADC calib b read from EE: %f\r\n", s_analog.cal_b);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_LEAD_R, &c)) {
s_analog.lead_resistance = ((x32_t) { .u = c }).f;
PRINTF("ADC calib R_LEAD read from EE: %f\r\n", s_analog.lead_resistance);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_REF_R, &c)) {
s_analog.reference_resistor = ((x32_t) { .u = c }).f;
PRINTF("ADC calib R_REF read from EE: %f\r\n", s_analog.reference_resistor);
}
correct_invalid_calib();
LL_ADC_Enable(ADC_TEMP);
LL_ADC_StartCalibration(ADC_TEMP);
@ -152,27 +384,53 @@ void app_analog_init()
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 4);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_ADC_EnableIT_EOS(ADC_TEMP);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_ADC_REG_StartConversionExtTrig(ADC_TEMP, LL_ADC_REG_TRIG_EXT_RISING);
LL_ADC_REG_StartConversionSWStart(ADC_TEMP);
// LL_ADC_REG_StartConversionSWStart(ADC_TEMP);
// this timer runs with 1 kHz clock
LL_TIM_SetTriggerOutput(TIM1, LL_TIM_TRGO_CC1IF);
LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1);
LL_TIM_EnableAllOutputs(TIM1); // TIM1 needs outputs specially enabled - it's "advanced timer"
LL_TIM_EnableCounter(TIM1);
}
static float val_to_c(float val)
float val_to_c(float x)
{
// val is the ratio
float pt100r = (x * s_analog.lead_resistance + x * s_analog.reference_resistor - s_analog.lead_resistance) / (1 - x);
// TODO use binary search.. lol
for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) {
float cur = TSENSE_LOOKUP[i];
if (cur >= val) {
float prev = TSENSE_LOOKUP[i - 1];
float cur = PT100_LOOKUP[i];
if (cur >= pt100r) {
float prev = PT100_LOOKUP[i - 1];
float ratio = (val - prev) / (cur - prev);
float ratio = (pt100r - prev) / (cur - prev);
return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP;
}
}
return TSENSE_T_MAX;
}
float c_to_val(float cf)
{
int lower = (int) (cf / TSENSE_T_STEP);
if (lower < 0) {
lower = 0;
}
if (lower >= TSENSE_LOOKUP_LEN - 1) {
lower = TSENSE_LOOKUP_LEN - 2;
}
int upper = lower + 1;
float ratio = (cf - ((float)lower * TSENSE_T_STEP)) / 5.0f;
return PT100_LOOKUP[lower] + (PT100_LOOKUP[upper] - PT100_LOOKUP[lower]) * ratio;
}
void app_temp_sample()
{
uint32_t sums[4] = {};
@ -190,28 +448,38 @@ void app_temp_sample()
return;
}
s_analog.adc_averages[0] = (float) sums[0] / count;
s_analog.adc_averages[1] = (float) sums[1] / count;
s_analog.adc_averages[2] = (float) sums[2] / count;
s_analog.adc_averages[3] = (float) sums[3] / count;
float adc_averages[4];
adc_averages[0] = (float) sums[0] / count;
adc_averages[1] = (float) sums[1] / count;
adc_averages[2] = (float) sums[2] / count;
adc_averages[3] = (float) sums[3] / count;
// PRINTF("%f\t%f\t%f\t%f\r\n",
// adc_averages[0],
// adc_averages[1],
// adc_averages[2],
// adc_averages[3]
// );
/* r_pt100, r_ref, internal_temp, v_ref_int */
float refint = s_analog.adc_averages[3];
float refint = adc_averages[3];
float scale = V_REFINT / refint;
const float avg_slope = 4.3f * scale;
const float v25 = 1.43f;
const float v_tsen = s_analog.adc_averages[2] * scale;
const float v_tsen = adc_averages[2] * scale;
s_analog.soc_temp = (v25 - v_tsen) / avg_slope + 25.f;
s_analog.v_sensor = s_analog.adc_averages[0] * scale; // good for debug/tuning
//s_analog.v_sensor = adc_averages[0] * scale; // good for debug/tuning
// using a voltage divider, so assuming the reference resistor is measured well,
// we can just use the ratio and the exact voltage value is not important.
float actual_temp = val_to_c(s_analog.adc_averages[0] / s_analog.adc_averages[1]);
s_analog.oventemp_history[s_analog.oventemp_history_ptr] = actual_temp;
float oventemp_sample = adc_averages[0] / adc_averages[1];
s_analog.oventemp_history[s_analog.oventemp_history_ptr] = oventemp_sample;
s_analog.oventemp_history_ptr = (s_analog.oventemp_history_ptr + 1) % OVENTEMP_HISTORY_DEPTH;
float sum = 0;
@ -225,7 +493,27 @@ void app_temp_sample()
if (depth > 0) {
sum /= depth;
}
s_analog.oven_temp = sum;
float y = s_analog.cal_a * sum + s_analog.cal_b;
//float y = sum;
float actual_temp = val_to_c(y);
PRINTF("T Raw[%f] * A[%f] + B[%f]-> %f, temp %f°C\r\n", sum, s_analog.cal_a, s_analog.cal_b, y, actual_temp);
s_analog.oven_temp = actual_temp;
s_analog.oven_temp_raw = sum;
app_safety_pass_temp_calculation();
if (s_analog.oven_temp_raw >= 0.05 && s_analog.oven_temp_raw <= 0.22) {
app_safety_pass_temp_normal();
}
if (s_analog.soc_temp >= 2.0 && s_analog.soc_temp <= 90.0) {
app_safety_pass_soc_temp_ok();
} else {
PRINTF("SOC OVERHEAT!! %f\r\n", s_analog.soc_temp);
}
}
float app_temp_read_oven()
@ -233,6 +521,11 @@ float app_temp_read_oven()
return s_analog.oven_temp;
}
float app_temp_read_oven_raw()
{
return s_analog.oven_temp_raw;
}
float app_temp_read_soc()
{
return s_analog.soc_temp;
@ -240,6 +533,8 @@ float app_temp_read_soc()
void app_temp_adc_eos()
{
app_safety_pass_adc_sampling();
// notify
memcpy((void *) &s_analog.adc_averagebuf[s_analog.averagebuf_ptr * 4], (const void *) adc_values, 4 * sizeof(uint16_t));
s_analog.averagebuf_ptr = (s_analog.averagebuf_ptr + 1) % AVERAGEBUF_DEPTH;
@ -247,5 +542,5 @@ void app_temp_adc_eos()
void app_temp_show_buf()
{
printf("%d,%d,%d,%d\r\n", adc_values[0], adc_values[1], adc_values[2], adc_values[3]);
PRINTF("%d,%d,%d,%d\r\n", adc_values[0], adc_values[1], adc_values[2], adc_values[3]);
}

@ -7,6 +7,20 @@
void app_analog_init();
float val_to_c(float val);
float c_to_val(float c);
void app_temp_set_calib_persistent(float a, float b);
void app_temp_set_calib_persistent_r(float lead, float reference);
void app_temp_backup_calib();
void app_temp_set_calib_temporary(float a, float b);
void app_temp_set_calib_temporary_r(float lead, float reference);
void app_temp_get_calib(float *a, float *b, float *l, float *r);
void app_temp_restore_calib();
/**
* Update temperature measurement.
*
@ -20,6 +34,9 @@ void app_temp_sample();
/// The value is valid after calling app_temp_sample()
float app_temp_read_oven();
/// Get the raw ADC value (divider voltage)
float app_temp_read_oven_raw();
/// Read current SOC temperature (celsius)
/// The value is valid after calling app_temp_sample()
float app_temp_read_soc();

@ -0,0 +1,49 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file crc.c
* @brief This file provides code for the configuration
* of the CRC instances.
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "crc.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* CRC init function */
void MX_CRC_Init(void)
{
/* USER CODE BEGIN CRC_Init 0 */
/* USER CODE END CRC_Init 0 */
/* Peripheral clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC);
/* USER CODE BEGIN CRC_Init 1 */
/* USER CODE END CRC_Init 1 */
/* USER CODE BEGIN CRC_Init 2 */
/* USER CODE END CRC_Init 2 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

@ -0,0 +1,25 @@
//
// Created by MightyPork on 2023/04/09.
//
#ifndef TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
#define TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
enum EEAddresses {
// 1.0
EE_ADDR_CAL_A = 1,
// 0.0
EE_ADDR_CAL_B = 2,
// 10.0
EE_ADDR_PID_P = 3,
// 0.052
EE_ADDR_PID_I = 4,
// 100.0
EE_ADDR_PID_D = 5,
EE_ADDR_LEAD_R = 6,
EE_ADDR_REF_R = 7,
};
#endif //TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H

@ -25,7 +25,7 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "snprintf.h"
/* USER CODE END Includes */
@ -66,7 +66,7 @@ const osThreadAttr_t mainTsk_attributes = {
};
/* Definitions for heaterTsk */
osThreadId_t heaterTskHandle;
uint32_t heaterTskBuffer[ 128 ];
uint32_t heaterTskBuffer[ 300 ];
osStaticThreadDef_t heaterTskControlBlock;
const osThreadAttr_t heaterTsk_attributes = {
.name = "heaterTsk",
@ -78,7 +78,7 @@ const osThreadAttr_t heaterTsk_attributes = {
};
/* Definitions for guiTsk */
osThreadId_t guiTskHandle;
uint32_t guiTskBuffer[ 256 ];
uint32_t guiTskBuffer[ 300 ];
osStaticThreadDef_t guiTskControlBlock;
const osThreadAttr_t guiTsk_attributes = {
.name = "guiTsk",
@ -90,7 +90,7 @@ const osThreadAttr_t guiTsk_attributes = {
};
/* Definitions for guiEventQue */
osMessageQueueId_t guiEventQueHandle;
uint8_t guiEventQueBuffer[ 16 * 8 ];
uint8_t guiEventQueBuffer[ 32 * 1 ];
osStaticMessageQDef_t guiEventQueControlBlock;
const osMessageQueueAttr_t guiEventQue_attributes = {
.name = "guiEventQue",
@ -107,6 +107,22 @@ const osTimerAttr_t beepTimer_attributes = {
.cb_mem = &beepTimerControlBlock,
.cb_size = sizeof(beepTimerControlBlock),
};
/* Definitions for buttonPushTimer */
osTimerId_t buttonPushTimerHandle;
osStaticTimerDef_t buttonPushTimerControlBlock;
const osTimerAttr_t buttonPushTimer_attributes = {
.name = "buttonPushTimer",
.cb_mem = &buttonPushTimerControlBlock,
.cb_size = sizeof(buttonPushTimerControlBlock),
};
/* Definitions for buttonReleaseTimer */
osTimerId_t buttonReleaseTimerHandle;
osStaticTimerDef_t buttonReleaseTimerControlBlock;
const osTimerAttr_t buttonReleaseTimer_attributes = {
.name = "buttonReleaseTimer",
.cb_mem = &buttonReleaseTimerControlBlock,
.cb_size = sizeof(buttonReleaseTimerControlBlock),
};
/* Definitions for heaterMutex */
osMutexId_t heaterMutexHandle;
osStaticMutexDef_t heaterMutexControlBlock;
@ -125,6 +141,7 @@ void app_task_main(void *argument);
extern void app_task_heater(void *argument);
extern void app_task_gui(void *argument);
extern void app_beep_end(void *argument);
extern void app_push_debounce(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
@ -135,7 +152,7 @@ void vApplicationMallocFailedHook(void);
/* USER CODE BEGIN 4 */
void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
{
printf("vApplicationStackOverflowHook: %s\r\n", pcTaskName);
PRINTF("vApplicationStackOverflowHook: %s\r\n", pcTaskName);
/* Run time stack overflow checking is performed if
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is
called if a stack overflow is detected. */
@ -145,7 +162,7 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
/* USER CODE BEGIN 5 */
void vApplicationMallocFailedHook(void)
{
printf("vApplicationMallocFailedHook\r\n");
PUTS("vApplicationMallocFailedHook\r\n");
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
@ -184,13 +201,19 @@ void MX_FREERTOS_Init(void) {
/* creation of beepTimer */
beepTimerHandle = osTimerNew(app_beep_end, osTimerOnce, NULL, &beepTimer_attributes);
/* creation of buttonPushTimer */
buttonPushTimerHandle = osTimerNew(app_push_debounce, osTimerOnce, (void*) 1, &buttonPushTimer_attributes);
/* creation of buttonReleaseTimer */
buttonReleaseTimerHandle = osTimerNew(app_push_debounce, osTimerOnce, (void*) 0, &buttonReleaseTimer_attributes);
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the queue(s) */
/* creation of guiEventQue */
guiEventQueHandle = osMessageQueueNew (16, 8, &guiEventQue_attributes);
guiEventQueHandle = osMessageQueueNew (32, 1, &guiEventQue_attributes);
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
@ -223,7 +246,7 @@ void MX_FREERTOS_Init(void) {
* @retval None
*/
/* USER CODE END Header_app_task_main */
__attribute__((weak)) void app_task_main(void *argument)
__weak void app_task_main(void *argument)
{
/* USER CODE BEGIN app_task_main */
/* Infinite loop */

@ -44,6 +44,7 @@
void MX_GPIO_Init(void)
{
LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
@ -98,12 +99,27 @@ void MX_GPIO_Init(void)
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/**/
GPIO_InitStruct.Pin = KNOB_PUSH_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
LL_GPIO_Init(KNOB_PUSH_GPIO_Port, &GPIO_InitStruct);
LL_GPIO_AF_EnableRemap_PD01();
/**/
LL_GPIO_AF_EnableRemap_PD01();
LL_GPIO_AF_SetEXTISource(LL_GPIO_AF_EXTI_PORTB, LL_GPIO_AF_EXTI_LINE8);
/**/
EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_8;
EXTI_InitStruct.LineCommand = ENABLE;
EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
LL_EXTI_Init(&EXTI_InitStruct);
/**/
LL_GPIO_SetPinPull(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin, LL_GPIO_PULL_UP);
/**/
LL_GPIO_SetPinMode(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin, LL_GPIO_MODE_INPUT);
/* EXTI interrupt init*/
NVIC_SetPriority(EXTI9_5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
NVIC_EnableIRQ(EXTI9_5_IRQn);
}

@ -20,6 +20,7 @@
#include "main.h"
#include "cmsis_os.h"
#include "adc.h"
#include "crc.h"
#include "dma.h"
#include "iwdg.h"
#include "spi.h"
@ -58,6 +59,7 @@
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);
/* USER CODE BEGIN PFP */
@ -74,72 +76,74 @@ void MX_FREERTOS_Init(void);
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_AFIO);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
/* System interrupt init*/
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* PendSV_IRQn interrupt configuration */
NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),15, 0));
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),15, 0));
/* PendSV_IRQn interrupt configuration */
NVIC_SetPriority(PendSV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
/** NOJTAG: JTAG-DP Disabled and SW-DP Enabled
*/
LL_GPIO_AF_Remap_SWJ_NOJTAG();
/** NOJTAG: JTAG-DP Disabled and SW-DP Enabled
*/
LL_GPIO_AF_Remap_SWJ_NOJTAG();
/* USER CODE BEGIN Init */
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE BEGIN SysInit */
MX_DMA_Init();
/* USER CODE END SysInit */
MX_DMA_Init();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_IWDG_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
MX_DMA_Init();
MX_TIM4_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_IWDG_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
MX_DMA_Init();
MX_TIM4_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_SPI2_Init();
MX_TIM1_Init();
MX_CRC_Init();
/* USER CODE BEGIN 2 */
printf("Start.\r\n");
/* USER CODE END 2 */
PUTS("Start.\r\n");
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Init scheduler */
osKernelInitialize(); /* Call init function for freertos objects (in freertos.c) */
MX_FREERTOS_Init();
/* Start scheduler */
osKernelStart();
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
app_emergency_stop();
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
@ -148,46 +152,41 @@ int main(void)
*/
void SystemClock_Config(void)
{
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
while(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_2)
{
}
LL_RCC_HSI_SetCalibTrimming(16);
LL_RCC_HSI_Enable();
/* Wait till HSI is ready */
while(LL_RCC_HSI_IsReady() != 1)
{
}
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while(LL_RCC_LSI_IsReady() != 1)
{
}
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_16);
LL_RCC_PLL_Enable();
/* Wait till PLL is ready */
while(LL_RCC_PLL_IsReady() != 1)
{
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
/* Wait till System clock is ready */
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL)
{
}
LL_Init1msTick(64000000);
LL_SetSystemCoreClock(64000000);
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSRC_PCLK2_DIV_8);
LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);
while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) {
}
LL_RCC_HSI_SetCalibTrimming(16);
LL_RCC_HSI_Enable();
/* Wait till HSI is ready */
while (LL_RCC_HSI_IsReady() != 1) {
}
LL_RCC_LSI_Enable();
/* Wait till LSI is ready */
while (LL_RCC_LSI_IsReady() != 1) {
}
LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, LL_RCC_PLL_MUL_16);
LL_RCC_PLL_Enable();
/* Wait till PLL is ready */
while (LL_RCC_PLL_IsReady() != 1) {
}
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
/* Wait till System clock is ready */
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
}
LL_Init1msTick(64000000);
LL_SetSystemCoreClock(64000000);
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSRC_PCLK2_DIV_8);
}
/* USER CODE BEGIN 4 */
@ -200,17 +199,16 @@ void SystemClock_Config(void)
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
printf("Error_Handler\r\n");
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
PUTS("Error_Handler\r\n");
app_emergency_stop();
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
@ -220,9 +218,12 @@ void Error_Handler(void)
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
/* USER CODE BEGIN 6 */
PRINTF("assert_failed %s:%d", (const char *) file, (int) line);
app_emergency_stop();
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

@ -24,8 +24,10 @@
#include "task.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "app_temp.h"
#include "app_knob.h"
#include "app_heater.h"
#include <inttypes.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@ -62,6 +64,8 @@
/* USER CODE BEGIN EV */
bool EE_NMI_Callback();
/* USER CODE END EV */
/******************************************************************************/
@ -72,30 +76,189 @@
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
if (EE_NMI_Callback()) {
return;
}
app_emergency_stop();
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1) {
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
#define VERBOSE_HARDFAULT 1
#if VERBOSE_HARDFAULT
void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used. If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t stacked_r0;
volatile uint32_t stacked_r1;
volatile uint32_t stacked_r2;
volatile uint32_t stacked_r3;
volatile uint32_t stacked_r12;
volatile uint32_t stacked_lr; /* Link register. */
volatile uint32_t stacked_pc; /* Program counter. */
volatile uint32_t stacked_psr;/* Program status register. */
#if (__CORTEX_M >= 3)
uint32_t cfsr, hfsr, dfsr;
uint32_t bus_fault_address;
uint32_t memmanage_fault_address;
bus_fault_address = SCB->BFAR;
memmanage_fault_address = SCB->MMFAR;
cfsr = SCB->CFSR;
hfsr = SCB->HFSR;
dfsr = SCB->DFSR;
#endif
stacked_r0 = origStack[0];
stacked_r1 = origStack[1];
stacked_r2 = origStack[2];
stacked_r3 = origStack[3];
stacked_r12 = origStack[4];
stacked_lr = origStack[5];
stacked_pc = origStack[6];
stacked_psr = origStack[7];
app_heater_emergency_shutdown();
#define BS(reg, pos, str) (((reg)&(1<<(pos)))?(str" "):"")
#define REDPTR(val) (((val)&0xFF000000) != 0x08000000?"\033[31m":"\033[32m")
PRINTF("\r\n*** HARD FAULT ***\r\n\r\n");
PRINTF("- Stack frame:\r\n");
PRINTF(" R0 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r0);
PRINTF(" R1 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r1);
PRINTF(" R2 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r2);
PRINTF(" R3 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r3);
PRINTF(" R12 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r12);
PRINTF(" LR = %s0x%08"PRIX32"\033[m\r\n", REDPTR(stacked_lr), stacked_lr);
PRINTF(" PC = %s0x%08"PRIX32"\033[m\r\n", REDPTR(stacked_pc), stacked_pc);
PRINTF(" PSR = \033[36m0x%08"PRIX32"\033[m", stacked_psr);
uint32_t exc = stacked_psr & 0x3F;
PRINTF(" [ %s%s%s%s%s ]\r\n",
BS(stacked_psr, 31, "N"),
BS(stacked_psr, 30, "Z"),
BS(stacked_psr, 29, "C"),
BS(stacked_psr, 28, "V"),
//BS(stacked_psr, 24, "T"), - thumb, always ON
(exc==0)?"Thread":
(exc==2)?"NMI":
(exc==3)?"HardFault":
(exc==11)?"SVCall":
(exc==14)?"PendSV":
(exc==15)?"SysTick":
(exc>=16)?"IRQ":"Unknown"
);
#if (__CORTEX_M >= 3)
PRINTF("\r\n- FSR/FAR:\r\n");
PRINTF(" CFSR = \033[36m0x%08"PRIX32"\033[m\r\n", cfsr);
PRINTF(" UsageFault: \033[31;1m%s%s%s%s%s%s%s\033[m\r\n"
" BusFault: \033[31;1m%s%s%s%s%s%s%s%s\033[m\r\n"
" MemFault: \033[31;1m%s%s%s%s%s%s%s\033[m\r\n",
BS(cfsr, 0, "IAccViol"),
BS(cfsr, 1, "DAccViol"),
BS(cfsr, 3, "MUnstkErr"),
BS(cfsr, 4, "MStkErr"),
BS(cfsr, 5, "MLSPErr(FPU)"),
BS(cfsr, 7, "MMArValid"),
((cfsr&0xFF)?"":"\033[m- "),
BS(cfsr, 8, "IBusErr"),
BS(cfsr, 9, "PreciseErr"),
BS(cfsr, 10, "ImpreciseErr"),
BS(cfsr, 11, "UnstkErr"),
BS(cfsr, 12, "StkErr"),
BS(cfsr, 13, "LSPErr"),
BS(cfsr, 15, "BFArValid"),
((cfsr&0xFF00)?"":"\033[m- "),
BS(cfsr, 16, "UndefInstr"),
BS(cfsr, 17, "InvState"),
BS(cfsr, 18, "InvPC"),
BS(cfsr, 19, "NoCP"),
BS(cfsr, 24, "Unaligned"),
BS(cfsr, 25, "Div0"),
((cfsr&0xFFFF0000)?"":"\033[m- ")
);
PRINTF(" HFSR = \033[36m0x%08"PRIX32"\033[m", hfsr);
PRINTF(" [ %s%s%s]\r\n",
BS(hfsr, 31, "DebugEvt"),
BS(hfsr, 30, "Forced"),
BS(hfsr, 1, "VectTbl")
);
PRINTF(" DFSR = \033[36m0x%08"PRIX32"\033[m", dfsr);
PRINTF(" [ %s%s%s%s%s]\r\n",
BS(dfsr, 0, "Halted"),
BS(dfsr, 1, "Bkpt"),
BS(dfsr, 2, "DWtTrap"),
BS(dfsr, 3, "VCatch"),
BS(dfsr, 4, "External")
);
if (cfsr & 0x0080) PRINTF(" MMFAR = \033[33m0x%08"PRIX32"\033[m\r\n", memmanage_fault_address);
if (cfsr & 0x8000) PRINTF(" BFAR = \033[33m0x%08"PRIX32"\033[m\r\n", bus_fault_address);
PRINTF("\r\n- Misc\r\n");
PRINTF(" LR/EXC_RETURN= %s0x%08"PRIX32"\033[m\n", REDPTR(lr_value), lr_value);
#endif
while (1);
}
#endif
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
* @brief This function handles Hard fault interrupt.
*/
void __attribute__((naked)) HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
printf("HardFault_Handler\r\n");
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
#if VERBOSE_HARDFAULT
// __asm volatile
// (
// " tst lr, #4 \n"
// " ite eq \n"
// " mrseq r0, msp \n"
// " mrsne r0, psp \n"
// " ldr r1, [r0, #24] \n"
// " mov r2, lr \n"
// " ldr r3, handler2_address_const \n"
// " bx r3 \n"
// " handler2_address_const: .word HardFault_DumpRegisters \n"
// );
//
__asm volatile( ".syntax unified\n"
"MOVS R0, #4 \n"
"MOV R1, LR \n"
"TST R0, R1 \n"
"BEQ _MSP \n"
"MRS R0, PSP \n"
"B HardFault_DumpRegisters \n"
"_MSP: \n"
"MRS R0, MSP \n"
"B HardFault_DumpRegisters \n"
".syntax divided\n") ;
#else
app_emergency_stop();
PRINTF("*** HARD FAULT ***\r\n\r\n");
while (1);
#endif
}
/**
@ -103,15 +266,15 @@ void HardFault_Handler(void)
*/
void MemManage_Handler(void)
{
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
printf("MemManage_Handler\r\n");
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
PUTS("MemManage_Handler\r\n");
app_emergency_stop();
/* USER CODE END MemoryManagement_IRQn 0 */
while (1) {
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
}
/**
@ -119,15 +282,15 @@ void MemManage_Handler(void)
*/
void BusFault_Handler(void)
{
/* USER CODE BEGIN BusFault_IRQn 0 */
printf("BusFault_Handler\r\n");
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
/* USER CODE BEGIN BusFault_IRQn 0 */
PUTS("BusFault_Handler\r\n");
app_emergency_stop();
/* USER CODE END BusFault_IRQn 0 */
while (1) {
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
}
/**
@ -135,15 +298,15 @@ void BusFault_Handler(void)
*/
void UsageFault_Handler(void)
{
/* USER CODE BEGIN UsageFault_IRQn 0 */
printf("UsageFault_Handler\r\n");
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
/* USER CODE BEGIN UsageFault_IRQn 0 */
PUTS("UsageFault_Handler\r\n");
app_emergency_stop();
/* USER CODE END UsageFault_IRQn 0 */
while (1) {
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
}
/**
@ -151,12 +314,12 @@ void UsageFault_Handler(void)
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/**
@ -164,20 +327,19 @@ void DebugMon_Handler(void)
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
#if (INCLUDE_xTaskGetSchedulerState == 1 )
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
/* USER CODE END SysTick_IRQn 0 */
#if (INCLUDE_xTaskGetSchedulerState == 1)
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
#endif /* INCLUDE_xTaskGetSchedulerState */
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1 )
}
xPortSysTickHandler();
#if (INCLUDE_xTaskGetSchedulerState == 1)
}
#endif /* INCLUDE_xTaskGetSchedulerState */
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
@ -192,34 +354,40 @@ void SysTick_Handler(void)
*/
void DMA1_Channel1_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
app_temp_adc_eos();
LL_DMA_ClearFlag_TC1(DMA1);
}
/* USER CODE END DMA1_Channel1_IRQn 0 */
/* USER CODE END DMA1_Channel1_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
/* USER CODE END DMA1_Channel1_IRQn 1 */
/* USER CODE END DMA1_Channel1_IRQn 1 */
}
/**
* @brief This function handles ADC1 and ADC2 global interrupts.
* @brief This function handles EXTI line[9:5] interrupts.
*/
void ADC1_2_IRQHandler(void)
void EXTI9_5_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_2_IRQn 0 */
/* USER CODE BEGIN EXTI9_5_IRQn 0 */
bool state = LL_GPIO_IsInputPinSet(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
app_temp_adc_eos();
/* USER CODE END EXTI9_5_IRQn 0 */
if (LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8) != RESET) {
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8);
/* USER CODE BEGIN LL_EXTI_LINE_8 */
// if (LL_ADC_IsActiveFlag_EOS(ADC_TEMP)) {
// LL_ADC_ClearFlag_EOS(ADC_TEMP);
// app_temp_adc_eos();
// }
app_knob_push_isr(0 == state);
/* USER CODE END ADC1_2_IRQn 0 */
/* USER CODE END LL_EXTI_LINE_8 */
}
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
/* USER CODE BEGIN ADC1_2_IRQn 1 */
/* USER CODE END ADC1_2_IRQn 1 */
/* USER CODE END EXTI9_5_IRQn 1 */
}
/**
@ -227,12 +395,19 @@ void ADC1_2_IRQHandler(void)
*/
void TIM4_IRQHandler(void)
{
/* USER CODE BEGIN TIM4_IRQn 0 */
/* USER CODE BEGIN TIM4_IRQn 0 */
if (LL_TIM_IsActiveFlag_CC1(TIM4) || LL_TIM_IsActiveFlag_CC2(TIM4)) {
LL_TIM_ClearFlag_CC1(TIM4);
LL_TIM_ClearFlag_CC2(TIM4);
app_knob_turn_isr();
}
/* USER CODE END TIM4_IRQn 0 */
/* USER CODE BEGIN TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 0 */
/* USER CODE BEGIN TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 1 */
/* USER CODE END TIM4_IRQn 1 */
}
/* USER CODE BEGIN 1 */

@ -24,12 +24,68 @@
/* USER CODE END 0 */
/* TIM1 init function */
void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
// --- this timer is used to time ADC sampling. ---
/* USER CODE END TIM1_Init 0 */
LL_TIM_InitTypeDef TIM_InitStruct = {0};
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
LL_TIM_BDTR_InitTypeDef TIM_BDTRInitStruct = {0};
/* Peripheral clock enable */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
TIM_InitStruct.Prescaler = 64000;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 10;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct.RepetitionCounter = 0;
LL_TIM_Init(TIM1, &TIM_InitStruct);
LL_TIM_DisableARRPreload(TIM1);
LL_TIM_SetClockSource(TIM1, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1);
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.OCNState = LL_TIM_OCSTATE_DISABLE;
TIM_OC_InitStruct.CompareValue = 1;
TIM_OC_InitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct.OCNPolarity = LL_TIM_OCPOLARITY_HIGH;
TIM_OC_InitStruct.OCIdleState = LL_TIM_OCIDLESTATE_LOW;
TIM_OC_InitStruct.OCNIdleState = LL_TIM_OCIDLESTATE_LOW;
LL_TIM_OC_Init(TIM1, LL_TIM_CHANNEL_CH1, &TIM_OC_InitStruct);
LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1);
LL_TIM_SetTriggerOutput(TIM1, LL_TIM_TRGO_OC1REF);
LL_TIM_DisableMasterSlaveMode(TIM1);
TIM_BDTRInitStruct.OSSRState = LL_TIM_OSSR_DISABLE;
TIM_BDTRInitStruct.OSSIState = LL_TIM_OSSI_DISABLE;
TIM_BDTRInitStruct.LockLevel = LL_TIM_LOCKLEVEL_OFF;
TIM_BDTRInitStruct.DeadTime = 0;
TIM_BDTRInitStruct.BreakState = LL_TIM_BREAK_DISABLE;
TIM_BDTRInitStruct.BreakPolarity = LL_TIM_BREAK_POLARITY_HIGH;
TIM_BDTRInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_DISABLE;
LL_TIM_BDTR_Init(TIM1, &TIM_BDTRInitStruct);
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
}
/* TIM2 init function */
void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
// --- this timer generates the buzzer PWM. The PWM parameters are adjusted on the fly ---
/* USER CODE END TIM2_Init 0 */
LL_TIM_InitTypeDef TIM_InitStruct = {0};
@ -81,6 +137,8 @@ void MX_TIM3_Init(void)
/* USER CODE BEGIN TIM3_Init 0 */
// --- this timer generates the heater PWM. The duty is set as 640 * percent ---
/* USER CODE END TIM3_Init 0 */
LL_TIM_InitTypeDef TIM_InitStruct = {0};
@ -93,7 +151,7 @@ void MX_TIM3_Init(void)
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
TIM_InitStruct.Prescaler = 2000;
TIM_InitStruct.Prescaler = 1000;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 64000;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
@ -117,11 +175,11 @@ void MX_TIM3_Init(void)
/**TIM3 GPIO Configuration
PA6 ------> TIM3_CH1
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
GPIO_InitStruct.Pin = PWM_HEATER_Pin;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
LL_GPIO_Init(PWM_HEATER_GPIO_Port, &GPIO_InitStruct);
}
/* TIM4 init function */
@ -130,6 +188,8 @@ void MX_TIM4_Init(void)
/* USER CODE BEGIN TIM4_Init 0 */
// --- This timer captures the rotary encoder. The count must be divided by 4, but it can't be done by the hardware, doesn't work well. ---
/* USER CODE END TIM4_Init 0 */
LL_TIM_InitTypeDef TIM_InitStruct = {0};
@ -159,7 +219,7 @@ void MX_TIM4_Init(void)
LL_TIM_SetEncoderMode(TIM4, LL_TIM_ENCODERMODE_X2_TI1);
LL_TIM_IC_SetActiveInput(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
LL_TIM_IC_SetPrescaler(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
LL_TIM_IC_SetFilter(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
LL_TIM_IC_SetFilter(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV32_N8);
LL_TIM_IC_SetPolarity(TIM4, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);
LL_TIM_IC_SetActiveInput(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI);
LL_TIM_IC_SetPrescaler(TIM4, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);

@ -0,0 +1,15 @@
//
// Created by MightyPork on 2023/04/09.
//
#ifndef TOASTER_OVEN_BLUEPILL_TRANSMUTE_H
#define TOASTER_OVEN_BLUEPILL_TRANSMUTE_H
#include <stdint.h>
typedef union x32 {
uint32_t u;
float f;
} x32_t;
#endif //TOASTER_OVEN_BLUEPILL_TRANSMUTE_H

@ -0,0 +1,52 @@
/**
* TODO file description
*/
#include <string.h>
#include "uart_stdout.h"
#include "FreeRTOS.h"
#include "main.h"
#define USE_CRITICAL 0
void stdout_putchar(char c) {
#if USE_CRITICAL
portENTER_CRITICAL();
#endif
while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {}
LL_USART_TransmitData8(USART_DEBUG, c);
while (!LL_USART_IsActiveFlag_TC(USART_DEBUG)) {}
#if USE_CRITICAL
portEXIT_CRITICAL();
#endif
}
void stdout_write(const char *pcBuffer, const size_t iLength) {
#if USE_CRITICAL
portENTER_CRITICAL();
#endif
while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {}
int cnt = (int) iLength;
while (cnt-- > 0) {
char c = *pcBuffer++;
LL_USART_TransmitData8(USART_DEBUG, c);
while (!LL_USART_IsActiveFlag_TC(USART_DEBUG)) {}
}
#if USE_CRITICAL
portEXIT_CRITICAL();
#endif
}
void stdout_puts(const char *pcBuffer) {
stdout_write(pcBuffer, strlen(pcBuffer));
}
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
int _write(int fd, const char *pcBuffer, const int iLength) {
stdout_write(pcBuffer, iLength);
return iLength;
}

@ -0,0 +1,8 @@
/**
* TODO file description
*/
#ifndef BLUEPILLTROUBA_UART_STDOUT_H
#define BLUEPILLTROUBA_UART_STDOUT_H
#endif //BLUEPILLTROUBA_UART_STDOUT_H

@ -21,7 +21,6 @@
#include "usart.h"
/* USER CODE BEGIN 0 */
#include "main.h"
/* USER CODE END 0 */
/* USART1 init function */
@ -52,7 +51,8 @@ void MX_USART1_UART_Init(void)
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING;
GPIO_InitStruct.Mode = LL_GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART1_Init 1 */
@ -75,18 +75,4 @@ void MX_USART1_UART_Init(void)
}
/* USER CODE BEGIN 1 */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
int _write(int fd, const char *pcBuffer, const int iLength) {
int cnt = iLength;
while (cnt-- > 0) {
while (!LL_USART_IsActiveFlag_TXE(USART_DEBUG)) {}
LL_USART_TransmitData8(USART_DEBUG, *pcBuffer++);
}
return iLength;
}
/* USER CODE END 1 */

@ -0,0 +1,204 @@
/**
******************************************************************************
* @file stm32f1xx_ll_crc.h
* @author MCD Application Team
* @brief Header file of CRC LL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32F1xx_LL_CRC_H
#define STM32F1xx_LL_CRC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx.h"
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined(CRC)
/** @defgroup CRC_LL CRC
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup CRC_LL_Exported_Constants CRC Exported Constants
* @{
*/
/**
* @}
*/
/* Exported macro ------------------------------------------------------------*/
/** @defgroup CRC_LL_Exported_Macros CRC Exported Macros
* @{
*/
/** @defgroup CRC_LL_EM_WRITE_READ Common Write and read registers Macros
* @{
*/
/**
* @brief Write a value in CRC register
* @param __INSTANCE__ CRC Instance
* @param __REG__ Register to be written
* @param __VALUE__ Value to be written in the register
* @retval None
*/
#define LL_CRC_WriteReg(__INSTANCE__, __REG__, __VALUE__) WRITE_REG(__INSTANCE__->__REG__, __VALUE__)
/**
* @brief Read a value in CRC register
* @param __INSTANCE__ CRC Instance
* @param __REG__ Register to be read
* @retval Register value
*/
#define LL_CRC_ReadReg(__INSTANCE__, __REG__) READ_REG(__INSTANCE__->__REG__)
/**
* @}
*/
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup CRC_LL_Exported_Functions CRC Exported Functions
* @{
*/
/** @defgroup CRC_LL_EF_Configuration CRC Configuration functions
* @{
*/
/**
* @brief Reset the CRC calculation unit.
* @note If Programmable Initial CRC value feature
* is available, also set the Data Register to the value stored in the
* CRC_INIT register, otherwise, reset Data Register to its default value.
* @rmtoll CR RESET LL_CRC_ResetCRCCalculationUnit
* @param CRCx CRC Instance
* @retval None
*/
__STATIC_INLINE void LL_CRC_ResetCRCCalculationUnit(CRC_TypeDef *CRCx)
{
SET_BIT(CRCx->CR, CRC_CR_RESET);
}
/**
* @}
*/
/** @defgroup CRC_LL_EF_Data_Management Data_Management
* @{
*/
/**
* @brief Write given 32-bit data to the CRC calculator
* @rmtoll DR DR LL_CRC_FeedData32
* @param CRCx CRC Instance
* @param InData value to be provided to CRC calculator between between Min_Data=0 and Max_Data=0xFFFFFFFF
* @retval None
*/
__STATIC_INLINE void LL_CRC_FeedData32(CRC_TypeDef *CRCx, uint32_t InData)
{
WRITE_REG(CRCx->DR, InData);
}
/**
* @brief Return current CRC calculation result. 32 bits value is returned.
* @rmtoll DR DR LL_CRC_ReadData32
* @param CRCx CRC Instance
* @retval Current CRC calculation result as stored in CRC_DR register (32 bits).
*/
__STATIC_INLINE uint32_t LL_CRC_ReadData32(CRC_TypeDef *CRCx)
{
return (uint32_t)(READ_REG(CRCx->DR));
}
/**
* @brief Return data stored in the Independent Data(IDR) register.
* @note This register can be used as a temporary storage location for one byte.
* @rmtoll IDR IDR LL_CRC_Read_IDR
* @param CRCx CRC Instance
* @retval Value stored in CRC_IDR register (General-purpose 8-bit data register).
*/
__STATIC_INLINE uint32_t LL_CRC_Read_IDR(CRC_TypeDef *CRCx)
{
return (uint32_t)(READ_REG(CRCx->IDR));
}
/**
* @brief Store data in the Independent Data(IDR) register.
* @note This register can be used as a temporary storage location for one byte.
* @rmtoll IDR IDR LL_CRC_Write_IDR
* @param CRCx CRC Instance
* @param InData value to be stored in CRC_IDR register (8-bit) between Min_Data=0 and Max_Data=0xFF
* @retval None
*/
__STATIC_INLINE void LL_CRC_Write_IDR(CRC_TypeDef *CRCx, uint32_t InData)
{
*((uint8_t __IO *)(&CRCx->IDR)) = (uint8_t) InData;
}
/**
* @}
*/
#if defined(USE_FULL_LL_DRIVER)
/** @defgroup CRC_LL_EF_Init Initialization and de-initialization functions
* @{
*/
ErrorStatus LL_CRC_DeInit(CRC_TypeDef *CRCx);
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */
/**
* @}
*/
/**
* @}
*/
#endif /* defined(CRC) */
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32F1xx_LL_CRC_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,108 @@
/**
******************************************************************************
* @file stm32f1xx_ll_crc.c
* @author MCD Application Team
* @brief CRC LL module driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
#if defined(USE_FULL_LL_DRIVER)
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_ll_crc.h"
#include "stm32f1xx_ll_bus.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif/* USE_FULL_ASSERT */
/** @addtogroup STM32F1xx_LL_Driver
* @{
*/
#if defined (CRC)
/** @addtogroup CRC_LL
* @{
*/
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup CRC_LL_Exported_Functions
* @{
*/
/** @addtogroup CRC_LL_EF_Init
* @{
*/
/**
* @brief De-initialize CRC registers (Registers restored to their default values).
* @param CRCx CRC Instance
* @retval An ErrorStatus enumeration value:
* - SUCCESS: CRC registers are de-initialized
* - ERROR: CRC registers are not de-initialized
*/
ErrorStatus LL_CRC_DeInit(CRC_TypeDef *CRCx)
{
ErrorStatus status = SUCCESS;
/* Check the parameters */
assert_param(IS_CRC_ALL_INSTANCE(CRCx));
if (CRCx == CRC)
{
/* Reset the CRC calculation unit */
LL_CRC_ResetCRCCalculationUnit(CRCx);
/* Reset IDR register */
LL_CRC_Write_IDR(CRCx, 0x00U);
}
else
{
status = ERROR;
}
return (status);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* defined (CRC) */
/**
* @}
*/
#endif /* USE_FULL_LL_DRIVER */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

@ -23,29 +23,23 @@
#define __EEPROM_EMUL_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#define __IO volatile
#define __weak __attribute__((weak))
#include "eeprom_emul_conf.h"
#include "eeprom_emul_types.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup EEPROM_Private_Constants EEPROM Private Constants
* @{
*/
/** @defgroup Private_Other_Constants Private Other Constants
* @{
*/
/* Page definitions */
#define PAGE_SIZE FLASH_PAGE_SIZE /*!< Page size */
#define PAGE_HEADER_SIZE EE_ELEMENT_SIZE * 4U /*!< Page Header is 4 elements to save page state */
#define PAGE_HEADER_SIZE (EE_ELEMENT_SIZE * 4U) /*!< Page Header is 4 elements to save page state */
#define NB_MAX_ELEMENTS_BY_PAGE ((PAGE_SIZE - PAGE_HEADER_SIZE) / EE_ELEMENT_SIZE) /*!< Max number of elements by page */
#define PAGES_NUMBER (((((NB_OF_VARIABLES + NB_MAX_ELEMENTS_BY_PAGE) / NB_MAX_ELEMENTS_BY_PAGE) * 2U) * CYCLES_NUMBER) + GUARD_PAGES_NUMBER)
/*!< Number of consecutives pages used by the application */
/*!< Number of consecutives pages used by the application */
#define NB_MAX_WRITTEN_ELEMENTS ((NB_MAX_ELEMENTS_BY_PAGE * PAGES_NUMBER) / 2U) /*!< Max number of elements written before triggering pages transfer */
#define START_PAGE PAGE(START_PAGE_ADDRESS) /*!< Page index of the 1st page used for EEPROM emul, in the bank */
#define END_EEPROM_ADDRESS (START_PAGE_ADDRESS + (PAGES_NUMBER * FLASH_PAGE_SIZE) - 1) /*!< Last address of EEPROM emulation flash pages */
@ -53,89 +47,44 @@
/* No page define */
#define EE_NO_PAGE_FOUND ((uint32_t)0xFFFFFFFFU)
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @defgroup EEPROM_Private_Macros EEPROM Private Macros
* @{
*/
/** @defgroup Macros_Pages Macros to manipulate pages
* @{
*/
/* Macros to manipulate pages */
#ifdef SECURE_FEATURES
#define PAGE_ADDRESS(__PAGE__) (uint32_t)(FLASH_BASE_NS + (__PAGE__) * PAGE_SIZE + ((START_PAGE_ADDRESS - FLASH_BASE_NS) / BANK_SIZE) * BANK_SIZE) /*!< Get page address from page index */
#define PAGE(__ADDRESS__) (uint32_t)((((__ADDRESS__) - FLASH_BASE_NS) % BANK_SIZE) / FLASH_PAGE_SIZE) /*!< Get page index from page address */
#else
#define PAGE_ADDRESS(__PAGE__) (uint32_t)(FLASH_BASE + (__PAGE__) * PAGE_SIZE + ((START_PAGE_ADDRESS - FLASH_BASE) / BANK_SIZE) * BANK_SIZE) /*!< Get page address from page index */
#define PAGE(__ADDRESS__) (uint32_t)((((__ADDRESS__) - FLASH_BASE) % BANK_SIZE) / FLASH_PAGE_SIZE) /*!< Get page index from page address */
#endif
#define PAGE_ADDRESS(__PAGE__) (uint32_t)(FLASH_BASE + (__PAGE__) * PAGE_SIZE + ((START_PAGE_ADDRESS - FLASH_BASE) / BANK_SIZE) * BANK_SIZE) /*!< Get page address from page index */
#define PAGE(__ADDRESS__) (uint32_t)((((__ADDRESS__) - FLASH_BASE) % BANK_SIZE) / FLASH_PAGE_SIZE) /*!< Get page index from page address */
#define PREVIOUS_PAGE(__PAGE__) (uint32_t)((((__PAGE__) - START_PAGE - 1U + PAGES_NUMBER) % PAGES_NUMBER) + START_PAGE) /*!< Get page index of previous page, among circular page list */
#define FOLLOWING_PAGE(__PAGE__) (uint32_t)((((__PAGE__) - START_PAGE + 1U) % PAGES_NUMBER) + START_PAGE) /*!< Get page index of following page, among circular page list */
/**
* @}
*/
/** @defgroup Macros_Elements Macros to manipulate elements
* @{
*/
/* Macros to manipulate elements */
#define EE_VIRTUALADDRESS_VALUE(__ELEMENT__) (EE_VIRTUALADDRESS_TYPE)((__ELEMENT__) & EE_MASK_VIRTUALADDRESS) /*!< Get virtual address value from element value */
#define EE_DATA_VALUE(__ELEMENT__) (EE_DATA_TYPE)(((__ELEMENT__) & EE_MASK_DATA) >> EE_DATA_SHIFT) /*!< Get Data value from element value */
#define EE_CRC_VALUE(__ELEMENT__) (EE_CRC_TYPE)(((__ELEMENT__) & EE_MASK_CRC) >> EE_CRC_SHIFT) /*!< Get Crc value from element value */
#define EE_ELEMENT_VALUE(__VIRTADDR__,__DATA__,__CRC__) (((EE_ELEMENT_TYPE)(__DATA__) << EE_DATA_SHIFT) | (__CRC__) << EE_CRC_SHIFT | (__VIRTADDR__)) /*!< Get element value from virtual addr, data and crc values */
/**
* @}
*/
#define EE_ELEMENT_VALUE(__VIRTADDR__, __DATA__, __CRC__) (((EE_ELEMENT_TYPE)(__DATA__) << EE_DATA_SHIFT) | (__CRC__) << EE_CRC_SHIFT | (__VIRTADDR__)) /*!< Get element value from virtual addr, data and crc values */
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/** @defgroup EEPROM_Exported_Functions EEPROM Exported Functions
* @{
*/
EE_Status EE_Format(EE_Erase_type EraseType);
EE_Status EE_Init(EE_Erase_type EraseType);
#if defined(EE_ACCESS_32BITS)
EE_Status EE_ReadVariable32bits(uint16_t VirtAddress, uint32_t* pData);
EE_Status EE_ReadVariable32bits(uint16_t VirtAddress, uint32_t *pData);
EE_Status EE_WriteVariable32bits(uint16_t VirtAddress, uint32_t Data);
#endif
#if defined(FLASH_LINES_128B)
EE_Status EE_ReadVariable96bits(uint16_t VirtAddress, uint64_t* pData);
EE_Status EE_WriteVariable96bits(uint16_t VirtAddress, uint64_t* Data);
#endif
EE_Status EE_ReadVariable16bits(uint16_t VirtAddress, uint16_t* pData);
EE_Status EE_ReadVariable16bits(uint16_t VirtAddress, uint16_t *pData);
EE_Status EE_WriteVariable16bits(uint16_t VirtAddress, uint16_t Data);
EE_Status EE_ReadVariable8bits(uint16_t VirtAddress, uint8_t* pData);
EE_Status EE_ReadVariable8bits(uint16_t VirtAddress, uint8_t *pData);
EE_Status EE_WriteVariable8bits(uint16_t VirtAddress, uint8_t Data);
EE_Status EE_CleanUp(void);
EE_Status EE_CleanUp_IT(void);
EE_Status EE_DeleteCorruptedFlashAddress(uint32_t Address);
void EE_EndOfCleanup_UserCallback(void);
/**
* @}
*/
EE_Status EE_DeleteCorruptedFlashAddress(uint32_t Address);
/**
* @}
*/
* Callback from NMI.
*
* @return true if handled by this library
*/
bool EE_NMI_Callback();
#endif /* __EEPROM_EMUL_H */

@ -27,64 +27,17 @@
#ifndef __EEPROM_EMUL_CONF_H
#define __EEPROM_EMUL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @defgroup Private_Configuration_Constants Private Configuration Constants
* @{
*/
/* Configuration of eeprom emulation in flash, can be custom */
#define START_PAGE_ADDRESS 0x08080000U /*!< Start address of the 1st page in flash, for EEPROM emulation */
#define START_PAGE_ADDRESS 0x800E000U /*!< Start address of the 1st page in flash, for EEPROM emulation */
#define CYCLES_NUMBER 1U /*!< Number of 10Kcycles requested, minimum 1 for 10Kcycles (default),
for instance 10 to reach 100Kcycles. This factor will increase
pages number */
#define GUARD_PAGES_NUMBER 2U /*!< Number of guard pages avoiding frequent transfers (must be multiple of 2): 0,2,4.. */
/* Configuration of crc calculation for eeprom emulation in flash */
#define CRC_POLYNOMIAL_LENGTH LL_CRC_POLYLENGTH_16B /* CRC polynomial lenght 16 bits */
#define CRC_POLYNOMIAL_VALUE 0x8005U /* Polynomial to use for CRC calculation */
/**
* @}
*/
/**
* @}
*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup EEPROM_Exported_Constants EEPROM Exported Constants
* @{
*/
#define GUARD_PAGES_NUMBER 2U /*!< Number of guard pages avoiding frequent transfers (must be multiple of 2): 0,2,4.. */
/** @defgroup Exported_Configuration_Constants Exported Configuration Constants
* @{
*/
#define NB_OF_VARIABLES 1000U /*!< Number of variables to handle in eeprom */
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __EEPROM_EMUL_CONF_H */

@ -17,7 +17,7 @@
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __EEPROM_EMUL_TYPES_H
#define __EEPROM_EMUL_TYPES_H
@ -67,7 +67,7 @@ typedef enum {
/* External return code : action required */
EE_CLEANUP_REQUIRED = 0x100U,
#ifdef DUALCORE_FLASH_SHARING
/* Value returned when a program or erase operation is requested but
* the flash is already used by CPU2 */

@ -1,258 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32C0/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#ifdef FLASH_BANK_2
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t page_error = 0U;
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
#ifdef FLASH_BANK_2
uint32_t bank = GetBankNumber(PAGE_ADDRESS(Page));
s_eraseinit.Banks = bank;
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* No flush needed. There is no D-Cache for the STM32G0x0 and STM32G0x1 products. */
return;
}
#ifdef FLASH_BANK_2
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (OB_USER_DUALBANK_SWAP_DISABLE)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
#if defined(FLASH_DBANK_SUPPORT)
uint32_t bank = GetBankNumber(Address);
if(bank == FLASH_BANK_1)
{
while(FLASH->SR & FLASH_SR_BSY1)
{
}
}
else
{
while(FLASH->SR & FLASH_SR_BSY2)
{
}
}
#else
while(FLASH->SR & FLASH_SR_BSY1)
{
}
#endif
/* Check if error occured */
if((FLASH->SR & FLASH_SR_OPERR) || (FLASH->SR & FLASH_SR_PROGERR) ||
(FLASH->SR & FLASH_SR_WRPERR) || (FLASH->SR & FLASH_SR_PGAERR) ||
(FLASH->SR & FLASH_SR_SIZERR) || (FLASH->SR & FLASH_SR_PGSERR))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (FLASH->SR & FLASH_SR_EOP)
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_DBANK_SUPPORT)
EE_Status status;
/* Check the value of the DBANK user option byte */
if (OB_USER_DUALBANK_ENABLE)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,125 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32C0/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32c0xx_hal.h"
#include "stm32c0xx_ll_crc.h"
#include "stm32c0xx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1,173 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L4/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
#include "snprintf.h"
#include <inttypes.h>
static inline void FI_Raw_ProgramHalfword(uint32_t Address, uint16_t value)
{
*(__IO uint16_t *) (Address) = value;
/* Wait programmation completion */
while (FLASH->SR & FLASH_SR_BSY) {
}
}
static inline void FI_Raw_ProgramWord(uint32_t Address, uint32_t value)
{
FI_Raw_ProgramHalfword(Address, value & 0xFFFF);
FI_Raw_ProgramHalfword(Address + 2, value >> 16);
}
static void FI_Raw_ProgramDoubleWord(uint32_t Address, uint64_t value)
{
FI_Raw_ProgramWord(Address, value & 0xFFFFFFFFUL);
FI_Raw_ProgramWord(Address + 4, value >> 32);
}
/** @addtogroup EEPROM_Private_Functions
* @{
*/
static void UnlockFlash()
{
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
}
static void LockFlash()
{
FLASH->CR |= FLASH_CR_LOCK;
}
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
PRINTF("FI wr %p, val %016"PRIx64"\r\n", (void *) Address, Data);
EE_Status status = EE_OK;
if (FLASH->CR & FLASH_CR_LOCK) {
UnlockFlash();
}
/* Set FLASH Programmation bit */
FLASH->CR |= FLASH_CR_PG;
/* Program double word of value 0 */
FI_Raw_ProgramDoubleWord(Address, Data);
/* Check if error occured */
if (FLASH->SR & (FLASH_SR_WRPRTERR | FLASH_SR_PGERR)) {
PUTS("Flash write error\r\n");
status = EE_WRITE_ERROR;
}
/* Check FLASH End of Operation flag */
if (FLASH->SR & FLASH_SR_EOP) {
/* Clear FLASH End of Operation pending bit */
FLASH->SR = FLASH_SR_EOP;
}
/* Clear FLASH Programmation bit */
FLASH->CR &= ~FLASH_CR_PG;
LockFlash();
return status;
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
PRINTF("FI erase page %d, nbr %d\r\n", Page, NbPages);
EE_Status status = EE_OK;
if (FLASH->CR & FLASH_CR_LOCK) {
UnlockFlash();
}
/* Set FLASH Programmation bit */
FLASH->CR |= FLASH_CR_PER;
while (NbPages-- > 0) {
FLASH->AR = Page * FLASH_PAGE_SIZE;
FLASH->CR |= FLASH_CR_STRT;
/* Wait programmation completion */
while (FLASH->SR & FLASH_SR_BSY) {
}
Page++;
}
FLASH->CR &= ~FLASH_CR_PER;
LockFlash();
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
// f1 doesn't have cache
}
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status rv = FI_WriteDoubleWord(Address, 0);
if (rv == EE_WRITE_ERROR) {
rv = EE_DELETE_ERROR;
}
return rv;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -27,9 +27,29 @@
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"
#include "stm32l4xx_ll_crc.h"
#include "stm32l4xx_ll_bus.h"
#include <stdint.h>
#include "stm32f1xx.h"
#include "stm32f103xb.h"
#include "stm32f1xx_ll_crc.h"
#include "stm32f1xx_ll_bus.h"
/** @defgroup FLASHEx_Page_Size Page Size
* @{
*/
#if (defined(STM32F101x6) || defined(STM32F102x6) || defined(STM32F103x6) || defined(STM32F100xB) || defined(STM32F101xB) || defined(STM32F102xB) || defined(STM32F103xB))
#define FLASH_PAGE_SIZE 0x400U
#endif /* STM32F101x6 || STM32F102x6 || STM32F103x6 */
/* STM32F100xB || STM32F101xB || STM32F102xB || STM32F103xB */
#if (defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F103xE) || defined(STM32F101xG) || defined(STM32F103xG) || defined(STM32F105xC) || defined(STM32F107xC))
#define FLASH_PAGE_SIZE 0x800U
#endif /* STM32F100xB || STM32F101xB || STM32F102xB || STM32F103xB */
/* STM32F101xG || STM32F103xG */
/* STM32F105xC || STM32F107xC */
#define FLASH_BANK_SIZE (FLASH_BANK1_END - FLASH_BASE)
/** @addtogroup EEPROM_Emulation
* @{
@ -100,11 +120,9 @@
/** @addtogroup EEPROM_Private_Functions
* @{
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**

@ -1,265 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32G0/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#ifdef FLASH_BANK_2
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t page_error = 0U;
#ifdef FLASH_BANK_2
uint32_t bank = GetBankNumber(PAGE_ADDRESS(Page));
s_eraseinit.Banks = bank;
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
#ifdef FLASH_BANK_2
uint32_t bank = GetBankNumber(PAGE_ADDRESS(Page));
s_eraseinit.Banks = bank;
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* No flush needed. There is no D-Cache for the STM32G0x0 and STM32G0x1 products. */
return;
}
#ifdef FLASH_BANK_2
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (OB_USER_DUALBANK_SWAP_DISABLE)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
#if defined(FLASH_DBANK_SUPPORT)
uint32_t bank = GetBankNumber(Address);
if(bank == FLASH_BANK_1)
{
while(FLASH->SR & FLASH_SR_BSY1)
{
}
}
else
{
while(FLASH->SR & FLASH_SR_BSY2)
{
}
}
#else
while(FLASH->SR & FLASH_SR_BSY1)
{
}
#endif
/* Check if error occured */
if((FLASH->SR & FLASH_SR_OPERR) || (FLASH->SR & FLASH_SR_PROGERR) ||
(FLASH->SR & FLASH_SR_WRPERR) || (FLASH->SR & FLASH_SR_PGAERR) ||
(FLASH->SR & FLASH_SR_SIZERR) || (FLASH->SR & FLASH_SR_PGSERR))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (FLASH->SR & FLASH_SR_EOP)
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_DBANK_SUPPORT)
EE_Status status;
/* Check the value of the DBANK user option byte */
if (OB_USER_DUALBANK_ENABLE)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,125 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32G0/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32g0xx_hal.h"
#include "stm32g0xx_ll_crc.h"
#include "stm32g0xx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,280 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32G4/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#if defined(FLASH_BANK_2)
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1, page_error = 0U;
#if defined(FLASH_BANK_2)
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1;
#if defined(FLASH_BANK_2)
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* To keep its coherency, flush the D-Cache: its content is not updated after a flash erase. */
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_DATA_CACHE_ENABLE();
}
#if defined(FLASH_BANK_2)
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0U)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
uint32_t dcachetoreactivate = 0U;
EE_Status status = EE_OK;
/* Deactivate the data cache if they are activated to avoid data misbehavior */
if(READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) != RESET)
{
/* Disable data cache */
__HAL_FLASH_DATA_CACHE_DISABLE();
dcachetoreactivate = 1U;
}
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY))
{
}
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/* Flush the caches to be sure of the data consistency */
if(dcachetoreactivate == 1U)
{
/* Reset data cache */
__HAL_FLASH_DATA_CACHE_RESET();
/* Enable data cache */
__HAL_FLASH_DATA_CACHE_ENABLE();
}
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
sOBCfg.PCROPConfig = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,125 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32G4/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx_hal.h"
#include "stm32g4xx_ll_crc.h"
#include "stm32g4xx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,279 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L4/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#if defined(FLASH_BANK_2)
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1, page_error = 0U;
#if defined(FLASH_BANK_2)
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1;
#if defined(FLASH_BANK_2)
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* To keep its coherency, flush the D-Cache: its content is not updated after a flash erase. */
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_DATA_CACHE_ENABLE();
}
#if defined(FLASH_BANK_2)
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0U)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
uint32_t dcachetoreactivate = 0U;
EE_Status status = EE_OK;
/* Deactivate the data cache if they are activated to avoid data misbehavior */
if(READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) != RESET)
{
/* Disable data cache */
__HAL_FLASH_DATA_CACHE_DISABLE();
dcachetoreactivate = 1U;
}
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY))
{
}
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/* Flush the caches to be sure of the data consistency */
if(dcachetoreactivate == 1U)
{
/* Reset data cache */
__HAL_FLASH_DATA_CACHE_RESET();
/* Enable data cache */
__HAL_FLASH_DATA_CACHE_ENABLE();
}
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
sOBCfg.PCROPConfig = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,267 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L5/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
#ifdef FLASH_BANK_2
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
/* If TrustZone secure activated -> return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD_NS, Address, Data); */
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1, page_error = 0U;
#ifdef FLASH_BANK_2
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES; /* if TrustZone secure activated -> FLASH_TYPEERASE_PAGES_NS; */
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1;
#ifdef FLASH_BANK_2
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES; /* if TrustZone secure activated -> FLASH_TYPEERASE_PAGES_NS; */
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* No flush needed. EEPROM flash area is defined as non-cacheable thanks to the MPU in main.c. */
return;
}
#ifdef FLASH_BANK_2
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_SWAP_BANK) == 0U)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Wait for previous programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_NSSR_NSBSY))
{
}
/* Clear previous non-secure error programming flag */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
/* Set FLASH Programmation bit */
SET_BIT(FLASH->NSCR, FLASH_NSCR_NSPG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_NSSR_NSBSY))
{
}
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->NSCR, FLASH_NSCR_NSPG);
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,126 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L5/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l5xx_hal.h"
#include "stm32l5xx_ll_crc.h"
#include "stm32l5xx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
#define SECURE_FEATURE /*!< Informs the driver about the security features of the flash interface */
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,299 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L5/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint64_t FlashWord[2] =
{
0x0, 0x0
};
uint8_t FlashWord_status = 0; /* 0 is FlashWord is empty, 1 it is full */
const uint32_t QuadWord[4] =
{
0x00000000,
0x00000000,
0x00000000,
0x00000000
};
/* Private function prototypes -----------------------------------------------*/
#ifdef FLASH_BANK_2
static uint32_t GetBankNumber(uint32_t Address);
#endif
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a quad word at the given address in Flash (function is called FI_WriteDoubleWord to respect legacy for X-CUBE-EEPROM)
* @param Address Where to write
* @param Data What to write
* @param Write_type Type of writing on going (see EE_Write_type)
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
* - EE_FLASH_USED: flash currently used by CPU2
*/
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t* Data, EE_Write_type Write_type)
{
EE_Status status = EE_OK;
if(Write_type == EE_SET_PAGE)
{
FlashWord[0] = Data[0];
FlashWord[1] = Data[0];
}
else
{
FlashWord[0] = Data[0];
FlashWord[1] = Data[1];
}
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, Address, ((uint32_t)FlashWord)) != HAL_OK)
{
status = EE_WRITE_ERROR;
}
return status;
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1, page_error = 0U;
#ifdef FLASH_BANK_2
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES; /* if TrustZone secure activated -> FLASH_TYPEERASE_PAGES_NS; */
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t bank = FLASH_BANK_1;
#ifdef FLASH_BANK_2
bank = GetBankNumber(PAGE_ADDRESS(Page));
#endif
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES; /* if TrustZone secure activated -> FLASH_TYPEERASE_PAGES_NS; */
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
s_eraseinit.Banks = bank;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* No flush needed. EEPROM flash area is defined as non-cacheable thanks to the MPU in main.c. */
return;
}
#ifdef FLASH_BANK_2
/**
* @brief Gets the bank of a given address
* @param Address Address of the FLASH Memory
* @retval Bank_Number The bank of a given address
*/
static uint32_t GetBankNumber(uint32_t Address)
{
uint32_t bank = 0U;
if (READ_BIT(FLASH->OPTR, FLASH_OPTR_SWAP_BANK) == 0U)
{
/* No Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
}
else
{
/* Bank swap */
if (Address < (FLASH_BASE + FLASH_BANK_SIZE))
{
bank = FLASH_BANK_2;
}
else
{
bank = FLASH_BANK_1;
}
}
return bank;
}
#endif
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Wait for previous programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_NSSR_BSY))
{
}
/* Clear previous non-secure error programming flag */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
/* Set FLASH Programmation bit */
SET_BIT(FLASH->NSCR, FLASH_NSCR_PG);
/* Program quad word of value 0 */
// HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, Address, ((uint32_t)QuadWord));
*(__IO uint64_t*)(Address) = (uint64_t)0U;
*(__IO uint64_t*)(Address+8U) = (uint64_t)0U;
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_NSSR_BSY))
{
}
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->NSCR, FLASH_NSCR_PG);
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,126 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32L5/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32u5xx_hal.h"
#include "stm32u5xx_ll_crc.h"
#include "stm32u5xx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions */
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 16 Bytes (128 bits) element in flash */
/* Bit: 127 64 63 48 47 0 */
/* <--- Data Value -----> <-CRC-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 16U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint64_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint64_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFFFFFFFFFFU
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
#define SECURE_FEATURE /*!< Informs the driver about the security features of the flash interface */
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t* Data, EE_Write_type Write_type);
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,375 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32WB/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
#include "stm32wbxx_nucleo.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
#ifdef DUALCORE_FLASH_SHARING
#define HSEM_PROCESS_1 12U /* Number taken randomly to identify the process locking a semaphore in the driver context */
#endif
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
#ifdef DUALCORE_FLASH_SHARING
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @param Write_type Type of writing on going (see EE_Write_type)
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
* - EE_FLASH_USED: flash currently used by CPU2
*/
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t Data, EE_Write_type Write_type)
{
EE_Status ee_status = EE_OK;
/* We enter a critical section */
UTILS_ENTER_CRITICAL_SECTION();
/* When the ongoing writing operation is a direct one (no transfer is required,
we are not in init process, and we do not write the state of a page) */
if(Write_type == EE_SIMPLE_WRITE)
{
/* Wait for the semaphore to be free */
while( HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) );
/* Take the HW 7 semaphore */
if(HAL_HSEM_Take(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1) == HAL_OK)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data) != HAL_OK)
{
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
ee_status = EE_WRITE_ERROR;
}
/* Release the HW Semaphore */
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
ee_status = EE_OK;
}
else
{
/* If flash is used by CPU2, the semaphore release interrupt is activated so as to raise a notification when
the semaphore will be unlocked (user can do other operations while waiting) */
HAL_HSEM_ActivateNotification(__HAL_HSEM_SEMID_TO_MASK(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID));
ee_status = EE_FLASH_USED;
}
}
/* This is when the function call comes from a writing operation other than a direct one */
else
{
/* Wait for the semaphore 7 to be free and take it when it is */
while(HAL_HSEM_Take(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1) != HAL_OK)
{
while( HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) ) ;
}
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data) != HAL_OK)
{
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
ee_status = EE_WRITE_ERROR;
}
/* Release the HW Semaphore */
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
ee_status = EE_OK;
}
/* We exit the critical section */
UTILS_EXIT_CRITICAL_SECTION();
return ee_status;
}
#else
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
#endif
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
#ifdef DUALCORE_FLASH_SHARING
/* Wait for last operation to be completed */
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) ;
/* Because we want to share flash between CPU1 and 2, we erase each page individually
* and we take then release the associated semaphore for each page erasings.
* By doing this, we allow CPU2 to do urgent works between page erasings. */
for (uint32_t index = Page; index < (Page + NbPages); index++)
{
/* We enter a critical section */
UTILS_ENTER_CRITICAL_SECTION();
/* Wait for the semaphore 7 to be free and take it when it is */
while(HAL_HSEM_Take(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1) != HAL_OK)
{
while( HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) ) ;
}
/* Start erase page */
FLASH_PageErase(index);
/* Release the HW Semaphore */
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
/* We exit the critical section */
UTILS_EXIT_CRITICAL_SECTION();
/* Wait for last operation to be completed */
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) ;
}
/* If operation is completed or interrupted, disable the Page Erase Bit */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
/* Flush the caches to be sure of the data consistency */
/* Flush instruction cache */
if (READ_BIT(FLASH->ACR, FLASH_ACR_ICEN) == FLASH_ACR_ICEN)
{
/* Disable instruction cache */
__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
/* Reset instruction cache */
__HAL_FLASH_INSTRUCTION_CACHE_RESET();
/* Enable instruction cache */
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
}
/* Flush data cache */
if (READ_BIT(FLASH->ACR, FLASH_ACR_DCEN) == FLASH_ACR_DCEN)
{
/* Disable data cache */
__HAL_FLASH_DATA_CACHE_DISABLE();
/* Reset data cache */
__HAL_FLASH_DATA_CACHE_RESET();
/* Enable data cache */
__HAL_FLASH_DATA_CACHE_ENABLE();
}
#else
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t page_error = 0U;
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
#endif
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
#ifdef DUALCORE_FLASH_SHARING
/* We enter a critical section */
UTILS_ENTER_CRITICAL_SECTION();
/* Wait for the semaphore 7 to be free and take it when it is */
while(HAL_HSEM_Take(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1) != HAL_OK)
{
while( HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) ) ;
}
#endif
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
#ifdef DUALCORE_FLASH_SHARING
/* Release the HW Semaphore */
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
/* We exit the critical section */
UTILS_EXIT_CRITICAL_SECTION();
#endif
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* To keep its coherency, flush the D-Cache: its content is not updated after a flash erase. */
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_DATA_CACHE_ENABLE();
}
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
#ifdef DUALCORE_FLASH_SHARING
/* We enter a critical section */
UTILS_ENTER_CRITICAL_SECTION();
/* Wait for the semaphore 7 to be free and take it when it is */
while(HAL_HSEM_Take(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1) != HAL_OK)
{
while( HAL_HSEM_IsSemTaken(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID) ) ;
}
#endif
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
#ifdef DUALCORE_FLASH_SHARING
/* Release the HW Semaphore */
HAL_HSEM_Release(CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID, HSEM_PROCESS_1);
/* We exit the critical section */
UTILS_EXIT_CRITICAL_SECTION();
#endif
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) ;
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
sOBCfg.PCROPConfig = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,142 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32WB/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "stm32wbxx_hal.h"
#include "stm32wbxx_ll_crc.h"
#include "stm32wbxx_ll_bus.h"
#ifdef DUALCORE_FLASH_SHARING
#include "utilities_conf.h"
#include "hw_conf.h"
#include "shci.h"
#endif
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
#ifdef DUALCORE_FLASH_SHARING
#define EE_SEM_WAIT_TIMEOUT 5000U /*!< Take semaphore attempts timeout, 5s */
#endif
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/** @defgroup Macros_Flash Macros to access flash
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
#ifdef DUALCORE_FLASH_SHARING
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t Data, EE_Write_type Write_type);
#else
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
#endif
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,207 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32WL/flash_interface.c
* @author MCD Application Team
* @brief This file provides all the EEPROM emulation flash interface functions.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "flash_interface.h"
#include "stm32wlxx_nucleo.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
/**
* @brief Write a double word at the given address in Flash
* @param Address Where to write
* @param Data What to write
* @retval EE_Status
* - EE_OK: on success
* - EE_WRITE_ERROR: if an error occurs
*/
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data)
{
return HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, Data);
}
/**
* @brief Erase a page in polling mode
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
uint32_t page_error = 0U;
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase(&s_eraseinit, &page_error) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Erase a page with interrupt enabled
* @param Page Page number
* @param NbPages Number of pages to erase
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages)
{
EE_Status status = EE_OK;
FLASH_EraseInitTypeDef s_eraseinit;
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = NbPages;
s_eraseinit.Page = Page;
/* Erase the Page: Set Page status to ERASED status */
if (HAL_FLASHEx_Erase_IT(&s_eraseinit) != HAL_OK)
{
status = EE_ERASE_ERROR;
}
return status;
}
/**
* @brief Flush the caches if needed to keep coherency when the flash content is modified
*/
void FI_CacheFlush()
{
/* To keep its coherency, flush the D-Cache: its content is not updated after a flash erase. */
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_DATA_CACHE_ENABLE();
}
/**
* @brief Delete corrupted Flash address, can be called from NMI. No Timeout.
* @param Address Address of the FLASH Memory to delete
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address)
{
EE_Status status = EE_OK;
/* Set FLASH Programmation bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program double word of value 0 */
*(__IO uint32_t*)(Address) = (uint32_t)0U;
*(__IO uint32_t*)(Address+4U) = (uint32_t)0U;
/* Wait programmation completion */
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) ;
/* Check if error occured */
if((__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PROGERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGAERR)) ||
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_SIZERR)) || (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGSERR)))
{
status = EE_DELETE_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* Clear FLASH Programmation bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/* Clear FLASH ECCD bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ECCD);
return status;
}
/**
* @brief Check if the configuration is 128-bits bank or 2*64-bits bank
* @param None
* @retval EE_Status
* - EE_OK: on success
* - EE error code: if an error occurs
*/
EE_Status FI_CheckBankConfig(void)
{
#if defined (FLASH_OPTR_DBANK)
FLASH_OBProgramInitTypeDef sOBCfg;
EE_Status status;
/* Request the Option Byte configuration :
- User and RDP level are always returned
- WRP and PCROP are not requested */
sOBCfg.WRPArea = 0xFF;
sOBCfg.PCROPConfig = 0xFF;
HAL_FLASHEx_OBGetConfig(&sOBCfg);
/* Check the value of the DBANK user option byte */
if ((sOBCfg.USERConfig & OB_DBANK_64_BITS) != 0)
{
status = EE_OK;
}
else
{
status = EE_INVALID_BANK_CFG;
}
return status;
#else
/* No feature 128-bits single bank, so always 64-bits dual bank */
return EE_OK;
#endif
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -1,134 +0,0 @@
/**
******************************************************************************
* @file EEPROM_Emul/Porting/STM32WL/flash_interface.h
* @author MCD Application Team
* @brief This file contains all the functions prototypes for the EEPROM
* emulation flash interface.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_INTERFACE_H
#define __FLASH_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "eeprom_emul.h"
#include "stm32wlxx_hal.h"
#include "stm32wlxx_ll_crc.h"
#include "stm32wlxx_ll_bus.h"
/** @addtogroup EEPROM_Emulation
* @{
*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* Private types -------------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Constants
* @{
*/
/** @addtogroup Private_Other_Constants
* @{
*/
#define BANK_SIZE FLASH_BANK_SIZE /*!< Alias to FLASH_BANK_SIZE definition from HAL STM32L4 */
#define EE_ACCESS_32BITS /*!< Enable EEPROM 32bits R/W functions, only valid for flash allowing 64bits access*/
/* Page state header */
#define EE_PAGESTAT_ERASED (uint64_t)0xFFFFFFFFFFFFFFFFU /*!< State saved in 1st,2nd,3rd,4th data type of page header */
#define EE_PAGESTAT_RECEIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 1st data type of page header */
#define EE_PAGESTAT_ACTIVE (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 2nd data type of page header */
#define EE_PAGESTAT_VALID (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 3rd data type of page header */
#define EE_PAGESTAT_ERASING (uint64_t)0xAAAAAAAAAAAAAAAAU /*!< State saved in 4th data type of page header */
/* Description of the 8 Bytes (64 bits) element in flash */
/* Bit: 63 32 31 16 15 0 */
/* <--- Data Value -----> <-unused-> <-VirtAddr-> */
#define EE_ELEMENT_SIZE 8U /*!< Size of element in Bytes */
#define EE_ELEMENT_TYPE uint64_t /*!< Type of element */
#define EE_VIRTUALADDRESS_TYPE uint16_t /*!< Type of Virtual Address */
#define EE_VIRTUALADDRESS_SHIFT 0U /*!< Bits Shifting to get Virtual Address in element */
#define EE_CRC_TYPE uint16_t /*!< Type of Crc */
#define EE_CRC_SHIFT 16U /*!< Bits Shifting to get Crc in element */
#define EE_DATA_TYPE uint32_t /*!< Type of Data */
#define EE_DATA_SHIFT 32U /*!< Bits Shifting to get Data value in element */
#define EE_MASK_VIRTUALADDRESS (uint64_t)0x000000000000FFFFU
#define EE_MASK_CRC (uint64_t)0x00000000FFFF0000U
#define EE_MASK_DATA (uint64_t)0xFFFFFFFF00000000U
#define EE_MASK_FULL (uint64_t)0xFFFFFFFFFFFFFFFFU
/**
* @}
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Macros
* @{
*/
/** @defgroup Macros_Flash Macros to access flash
* @{
*/
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup EEPROM_Private_Functions
* @{
*/
#ifdef DUALCORE_FLASH_SHARING
EE_Status FI_WriteDoubleWord(uint32_t Address, uint64_t Data, EE_Write_type Write_type);
#else
HAL_StatusTypeDef FI_WriteDoubleWord(uint32_t Address, uint64_t Data);
#endif
EE_Status FI_PageErase(uint32_t Page, uint16_t NbPages);
EE_Status FI_PageErase_IT(uint32_t Page, uint16_t NbPages);
EE_Status FI_DeleteCorruptedFlashAddress(uint32_t Address);
EE_Status FI_CheckBankConfig(void);
void FI_CacheFlush(void);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* __FLASH_INTERFACE_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,44 @@
//
// Created by MightyPork on 2017/11/09.
//
// Small sprintf/snprintf implementation, used instead of the newlib one.
//
#ifndef GEX_SNPRINTF_H
#define GEX_SNPRINTF_H
#include <stdarg.h>
#include <limits.h>
int fixup_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
int fixup_snprintf(char *str, size_t count,const char *fmt,...);
int fixup_vasprintf(char **ptr, const char *format, va_list ap);
int fixup_asprintf(char **ptr, const char *format, ...);
int fixup_sprintf(char *ptr, const char *format, ...);
int fixup_printf(const char *format, ...);
int fixup_vprintf(const char *format, va_list ap);
#define VSNPRINTF(...) fixup_vsnprintf(__VA_ARGS__)
#define SNPRINTF(...) fixup_snprintf(__VA_ARGS__)
#define VASPRINTF(...) fixup_vasprintf(__VA_ARGS__)
#define ASPRINTF(...) fixup_asprintf(__VA_ARGS__)
#define SPRINTF(...) fixup_sprintf(__VA_ARGS__)
#define PRINTF(...) fixup_printf(__VA_ARGS__)
#define VPRINTF(...) fixup_vprintf(__VA_ARGS__)
// for debug
//#include <stdio.h>
//#define PRINTF(...) printf(__VA_ARGS__)
//#define SPRINTF(...) sprintf(__VA_ARGS__)
// extern
extern void stdout_puts(const char *s);
extern void stdout_putchar(char c);
extern void stdout_write(const char *s, size_t len);
#define PUTS(s) stdout_puts((s))
#define PUTCHAR(c) stdout_putchar((c))
#define WRITE(s, n) stdout_write((s), (n))
#endif //GEX_SNPRINTF_H

@ -20,6 +20,8 @@
/// Print characters 2x wider and taller
#define FONT_DOUBLE (FONT_DOUBLEW | FONT_DOUBLEH)
#define TEXT_CENTER 32
/// Print text stored in flash
void fb_text_P(fbpos_t x, fbpos_t y, const char *text, uint8_t flags, fbcolor_t color);

@ -27,6 +27,21 @@ void fb_text_P_or_RAM(fbpos_t x, fbpos_t y, const char *text, uint8_t flags, fbc
symh = 7;
}
const uint8_t pxw = (flags & FONT_DOUBLEW) ? 2 : 1;
const uint8_t pxh = (flags & FONT_DOUBLEH) ? 2 : 1;
if (flags & TEXT_CENTER) {
size_t len = utf8_strlen(text);
if (len == 0) {
return;
}
uint8_t charw = (symw + 1 + ((flags & FONT_BOLD) ? 1 : 0)) * pxw;
len *= charw;
len -= pxw;
x -= (fbpos_t) (len / 2);
}
while ((uchar = Utf8Iterator_Next(&iter)).uint) {
const uint8_t *data;
if (flags & FONT_4X5) {
@ -64,8 +79,6 @@ void fb_text_P_or_RAM(fbpos_t x, fbpos_t y, const char *text, uint8_t flags, fbc
}
} else {
// slow, pixel-by-pixel drawing
const uint8_t pxw = (flags & FONT_DOUBLEW) ? 2 : 1;
const uint8_t pxh = (flags & FONT_DOUBLEH) ? 2 : 1;
for(fbpos_t xx = 0; xx < symw; xx++) {
uint8_t column = pgm_read_byte(&data[xx]);
for(fbpos_t yy = 0; yy < symh; yy++) {

@ -99,4 +99,5 @@ static const font3x_bitmap_t PROGMEM font35_ascii[] = {
static const struct utf_glyph3x PROGMEM font35_extra[] = {
{.utf={.symbol="<EFBFBD>"}, {{0x1f, 0x1f, 0x1f}}},
{.utf={.symbol="°"}, {{0x07, 0x05, 0x07}}},
{.utf={.symbol=""}, {{0x15, 0x0e, 0x04}}},
};

@ -98,19 +98,15 @@ static const font5x_bitmap_t PROGMEM font57_ascii[] = {
static const struct utf_glyph5x PROGMEM font57_extra[] = {
{.utf={.symbol="<EFBFBD>"}, {{0x7f, 0x41, 0x41, 0x41, 0x7f}}},
{.utf={.symbol="×"}, {{0x22, 0x14, 0x08, 0x14, 0x22}}},
{.utf={.symbol=""}, {{0x08, 0x04, 0x3e, 0x04, 0x08}}},
{.utf={.symbol=""}, {{0x08, 0x10, 0x3e, 0x10, 0x08}}},
{.utf={.symbol=""}, {{0x08, 0x1c, 0x2a, 0x08, 0x08}}},
{.utf={.symbol=""}, {{0x08, 0x08, 0x2a, 0x1c, 0x08}}},
{.utf={.symbol=""}, {{0x1c, 0x22, 0x2e, 0x2a, 0x1c}}},
{.utf={.symbol=""}, {{0x63, 0x55, 0x4d, 0x55, 0x63}}},
{.utf={.symbol=""}, {{0x1c, 0x22, 0x2a, 0x22, 0x1c}}},
{.utf={.symbol=""}, {{0x10, 0x38, 0x54, 0x10, 0x1e}}},
{.utf={.symbol="🌡"}, {{0x20, 0x7e, 0x79, 0x7e, 0x2a}}},
{.utf={.symbol="°"}, {{0x00, 0x07, 0x05, 0x07, 0x00}}},
{.utf={.symbol="μ"}, {{0x7c, 0x20, 0x20, 0x10, 0x3c}}},
{.utf={.symbol="🔙"}, {{0x04, 0x4e, 0x55, 0x44, 0x38}}},
{.utf={.symbol=""}, {{0x7f, 0x3e, 0x1c, 0x08, 0x00}}},
{.utf={.symbol=""}, {{0x00, 0x08, 0x1c, 0x3e, 0x7f}}},
{.utf={.symbol="č"}, {{0x38, 0x45, 0x46, 0x45, 0x20}}},
{.utf={.symbol="š"}, {{0x48, 0x55, 0x56, 0x55, 0x20}}},
{.utf={.symbol="í"}, {{0x00, 0x44, 0x7d, 0x41, 0x00}}},
{.utf={.symbol="ž"}, {{0x44, 0x65, 0x56, 0x4d, 0x44}}},
{.utf={.symbol="ď"}, {{0x38, 0x44, 0x45, 0x48, 0x7f}}},
{.utf={.symbol="á"}, {{0x20, 0x54, 0x54, 0x55, 0x79}}},
{.utf={.symbol="»"}, {{0x22, 0x14, 0x2a, 0x14, 0x08}}},
{.utf={.symbol="ě"}, {{0x38, 0x55, 0x56, 0x55, 0x18}}},
};

@ -588,11 +588,18 @@ const char *font_extras[] = {
"xxx",
" ",
" ",
// Extra 2 "→"
"x ",
" x ",
"xxx",
" x ",
"x ",
};
const char *font_extras_utf[] = {
"<EFBFBD>",
"°",
"",
};
#include "fontedit_render.inc.c"

@ -775,30 +775,30 @@ const char *font_extras[] = {
"# #",
"# #",
"#####",
// Extra 1
" ",
"# #",
" # # ",
" # ",
" # # ",
"# #",
" ",
// Extra 2
" ",
" # ",
" ### ",
"# # #",
" # ",
" # ",
" ",
// Extra 3
" ",
" # ",
" # ",
"# # #",
" ### ",
" # ",
" ",
// // Extra 1
// " ",
// "# #",
// " # # ",
// " # ",
// " # # ",
// "# #",
// " ",
// // Extra 2
// " ",
// " # ",
// " ### ",
// "# # #",
// " # ",
// " # ",
// " ",
// // Extra 3
// " ",
// " # ",
// " # ",
// "# # #",
// " ### ",
// " # ",
// " ",
// Extra 4
" ",
" # ",
@ -815,105 +815,177 @@ const char *font_extras[] = {
" # ",
" # ",
" ",
// Extra 6
" ",
// // Extra 6
// " ",
// " ### ",
// "# # #",
// "# ###",
// "# #",
// " ### ",
// " ",
// // Extra 7
// "#####",
// "# #",
// " ### ",
// " # ",
// " # # ",
// "# #",
// "#####",
// // Extra 8
// " ",
// " ### ",
// "# #",
// "# # #",
// "# #",
// " ### ",
// " ",
// // Extra 9
// " ",
// " #",
// " # #",
// " # #",
// "#####",
// " # ",
// " # ",
// // Extra 10
// " # ",
// " # ##",
// " # # ",
// " ####",
// " ### ",
// "#####",
// " ### ",
// Extra 11
" ### ",
"# # #",
"# ###",
"# #",
" # # ",
" ### ",
" ",
// Extra 7
"#####",
"# #",
" ### ",
" # ",
" # # ",
"# #",
"#####",
// Extra 8
" ",
" ",
" ",
// // Extra 12
// " ",
// " ",
// "# #",
// "# #",
// "# ##",
// "### #",
// "# ",
// // Extra 13
// " # ",
// " # ",
// "#### ",
// " # #",
// " # #",
// " #",
// " ### ",
// // Extra 14
// "# ",
// "## ",
// "### ",
// "#### ",
// "### ",
// "## ",
// "# ",
// // Extra 15
// " #",
// " ##",
// " ###",
// " ####",
// " ###",
// " ##",
// " #",
// 99 "č"
" x x ",
" x ",
" ### ",
"# #",
"# # #",
"# ",
"# ",
"# #",
" ### ",
" ",
// Extra 9
" ",
// 115 "š"
" x x ",
" x ",
" ### ",
"# ",
" ### ",
" #",
" # #",
" # #",
"#####",
" # ",
"#### ",
// 105 "i"
" #x ",
" ",
" ## ",
" # ",
" # ",
// Extra 10
" # ",
" # ##",
" # # ",
" ####",
" ### ",
// 122 "z"
" x x ",
" x ",
"#####",
" ### ",
// Extra 11
" ### ",
" # # ",
" ### ",
" ",
" ",
" ",
" ",
// Extra 12
" ",
" ",
"# #",
"# #",
"# ##",
"### #",
"# ",
// Extra 13
" # ",
" # ",
" # ",
"#### ",
" # #",
" # #",
"#####",
// 100 "d"
" x #",
" #",
" ## #",
"# ##",
"# #",
"# #",
" ####",
// 97 "a"
" xx",
" ",
" ### ",
// Extra 14
"# ",
"## ",
"### ",
"#### ",
"### ",
"## ",
"# ",
// Extra 15
" #",
" ##",
" ###",
" ####",
" ###",
" ##",
" #",
"# #",
" ####",
// »
" ",
"x x ",
" x x ",
" x x",
" x x ",
"x x ",
" ",
// 101 "e"
" x x ",
" x ",
" ### ",
"# #",
"#####",
"# ",
" ### ",
};
const char *font_extras_utf[] = {
"<EFBFBD>",
"×",
"",
"",
// "×",
// "↑",
// "↓",
"",
"",
"", // clock
"",
"",
"",
"🌡",
// "⏱", // clock
// "⌛",
// "☸",
// "⏎",
// "🌡",
"°",
"μ",
"🔙", // back
"",
"",
// "μ",
// "⎌", // back
// "▶",
// "◀",
"č",
"š",
"í",
"ž",
"ď",
"á",
"»",
"ě",
};
#include "fontedit_render.inc.c"

@ -57,7 +57,7 @@ void fb_px(fbpos_t x, fbpos_t y, fbcolor_t color)
uint8_t fb_getpx(fbpos_t x, fbpos_t y)
{
if (x >= FBW || y >= FBH) { return 0; }
if (x >= FBW || y >= FBH || x < 0 || y < 0) { return 0; }
const fbpos_t row = y / 8;
const fbpos_t rowrem = y % 8;
const fbsize_t cell = (fbsize_t) x + (fbsize_t) row * FBW;
@ -70,7 +70,7 @@ uint8_t fb_getpx(fbpos_t x, fbpos_t y)
void fb_hline(fbpos_t x, fbpos_t y, fbpos_t w, fbcolor_t color)
{
if (x >= FBW || y >= FBH) { return; }
if (x >= FBW || y >= FBH || x < -w || y < 0) { return; }
w = MIN(FBW - x, w);
const fbpos_t row = y / 8;
const fbpos_t rowrem = y % 8;
@ -83,7 +83,7 @@ void fb_hline(fbpos_t x, fbpos_t y, fbpos_t w, fbcolor_t color)
void fb_vline(fbpos_t x, fbpos_t y, fbpos_t h, fbcolor_t color)
{
if (x >= FBW || y >= FBH) { return; }
if (x >= FBW || y >= FBH || x < 0 || y < -h) { return; }
h = MIN(FBH - y - 1, h);
const fbpos_t row = y / 8;
const fbpos_t rowrem = y % 8;
@ -116,7 +116,7 @@ void fb_vline(fbpos_t x, fbpos_t y, fbpos_t h, fbcolor_t color)
void fb_rect(fbpos_t x, fbpos_t y, fbpos_t w, fbpos_t h, fbcolor_t color)
{
if (x >= FBW || y >= FBH) { return; }
if (x >= FBW || y >= FBH || x < -w || y < -h) { return; }
w = MIN(FBW - x, w);
h = MIN(FBH - y, h);
const fbpos_t row = y / 8;
@ -232,19 +232,19 @@ void fb_circle(fbpos_t x0, fbpos_t y0, fbpos_t radius, uint8_t thickness, fbcolo
#if IS_AVR
void fb_bitmap_ex_P(fbpos_t x, fbpos_t y, fbpos_t w, fbpos_t h, const uint8_t *map, fbcolor_t color)
#else
void fb_bitmap_ex(fbpos_t x, fbpos_t y, fbpos_t w, fbpos_t h, const uint8_t *map, fbcolor_t color)
void fb_bitmap_ex(const fbpos_t x, const fbpos_t y, const fbpos_t w0, const fbpos_t h0, const uint8_t *map, fbcolor_t color)
#endif
{
if (x >= FBW || y >= FBH) { return; }
const fbpos_t w0 = w;
w = MIN(FBW - x - 1, w);
h = MIN(FBH - y - 1, h);
if (x >= FBW || y >= FBH || x < -w0 || y < -h0) { return; }
const fbpos_t w = MIN(FBW - x, w0);
fbpos_t h = MIN(FBH - y - 1, h0); // h is used as counter for rows
const fbpos_t row = y / 8;
const fbpos_t rowrem = y % 8;
fbsize_t cell = (fbsize_t) x + (fbsize_t) row * FBW;
const fbpos_t xskip = (x >= 0) ? 0 : (-x);
if (rowrem + h <= 8) {
for (fbpos_t i = 0; i < w; i++) {
for (fbpos_t i = xskip; i < w; i++) {
// all within one cell
const uint8_t mask = (pgm_read_byte(&map[i]) & (0xFF >> (8 - h))) << rowrem;
draw_mask(cell + i, mask, color);
@ -256,7 +256,7 @@ void fb_bitmap_ex(fbpos_t x, fbpos_t y, fbpos_t w, fbpos_t h, const uint8_t *map
// Draw the bitmap slice-by-slice based on how rows of the bitmap intersect with rows of the canvas.
// This could be optimized to walk each row of the canvas only once, but the code would get bigger.
while (h > 0) {
for (fbpos_t i = 0; i < w; i++) {
for (fbpos_t i = xskip; i < w; i++) {
const uint8_t mask = (pgm_read_byte(&map[i + mapc0]) & (0xFF >> rowrem)) << rowrem;
draw_mask(cell + i, mask, color);
}
@ -264,7 +264,7 @@ void fb_bitmap_ex(fbpos_t x, fbpos_t y, fbpos_t w, fbpos_t h, const uint8_t *map
cell += FBW;
if (rowrem != 0) {
for (fbpos_t i = 0; i < w; i++) {
for (fbpos_t i = xskip; i < w; i++) {
const uint8_t mask = (pgm_read_byte(&map[i + mapc0]) & (0xFF << (8 - rowrem))) >> (8 - rowrem);
draw_mask(cell + i, mask, color);
}

@ -99,10 +99,10 @@ void main() {
fb_text(15, 15, "MEOW", FONT_DOUBLEH, 1);
fb_text(40, 15, "MEOW", FONT_DOUBLEW, 1);
fb_text(40, 23, "MEOW", FONT_BOLD, 1);
fb_text(5, 5, "Tiny 3x5", FONT_3X5, 1);
fb_text(5, 5, "Tiny 3x5", FONT_3X5, 1);
fb_text(40, 5, "Tiny 4x5 MEOW", FONT_4X5, 1);
fb_frame(12,12,80,20,1,1);
// fb_text(36, 5, "-123456789.0 CPM°", FONT_TINY, 1);

@ -1,5 +1,5 @@
##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Sun Mar 12 14:42:27 CET 2023]
# File automatically-generated by tool: [projectgenerator] version: [3.16.0] date: [Tue Mar 14 20:49:50 CET 2023]
##########################################################################################################################
# ------------------------------------------------
@ -47,11 +47,20 @@ Core/Src/usart.c \
Core/Src/app_oled.c \
Core/Src/app_main.c \
Core/Src/app_pid.c \
Core/Src/app_gui.c \
Core/Src/Gui/app_gui.c \
Core/Src/Gui/screen_menu.c \
Core/Src/Gui/screen_home.c \
Core/Src/Gui/screen_manual.c \
Core/Src/Gui/screen_calibration.c \
Core/Src/Gui/screen_manual_menu.c \
Core/Src/Gui/screen_pid_tuning.c \
Core/Src/Gui/screen_calib_edit.c \
Core/Src/app_temp.c \
Core/Src/app_knob.c \
Core/Src/app_buzzer.c \
Core/Src/app_heater.c \
Core/Src/app_safety.c \
Core/Src/uart_stdout.c \
Core/Src/stm32f1xx_it.c \
Core/Src/system_stm32f1xx.c \
Middlewares/Third_Party/FreeRTOS/Source/croutine.c \
@ -64,8 +73,15 @@ Middlewares/Third_Party/FreeRTOS/Source/timers.c \
Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.c \
Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c \
Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c \
Lib/ufb/Src/framebuffer.c Lib/ufb/Src/utf8.c Lib/ufb/Src/font.c Lib/ufb/Src/fb_7seg.c Lib/ufb/Src/fb_text.c \
Lib/ufb/Src/framebuffer.c \
Lib/ufb/Src/utf8.c \
Lib/ufb/Src/font.c \
Lib/ufb/Src/fb_7seg.c \
Lib/ufb/Src/fb_text.c \
Lib/snprintf/snprintf.c \
Core/Src/dma.c \
Lib/EEPROM_Emul/Core/eeprom_emul.c \
Lib/EEPROM_Emul/Porting/STM32F1/flash_interface.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_gpio.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_adc.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_dma.c \
@ -75,7 +91,9 @@ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_exti.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_spi.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_tim.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_usart.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_pwr.c
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_pwr.c \
Core/Src/crc.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_crc.c
# ASM sources
ASM_SOURCES = \
@ -143,13 +161,17 @@ AS_INCLUDES = \
# C includes
C_INCLUDES = \
-ICore/Inc \
-ICore/Src \
-IDrivers/STM32F1xx_HAL_Driver/Inc \
-IMiddlewares/Third_Party/FreeRTOS/Source/include \
-IMiddlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 \
-IMiddlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3 \
-IDrivers/CMSIS/Device/ST/STM32F1xx/Include \
-IDrivers/CMSIS/Include \
-ILib/ufb/Inc
-ILib/ufb/Inc \
-ILib/snprintf \
-ILib/EEPROM_Emul/Core \
-ILib/EEPROM_Emul/Porting/STM32F1
# compile gcc flags
@ -211,7 +233,7 @@ $(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BUILD_DIR):
mkdir -p $@
.PHONY: all build flash clean flash flash-stlink analyze
.PHONY: all flash clean flash-stlink analyze size fonts
#######################################
# clean up
@ -228,11 +250,17 @@ clean:
build: all
flash-stlink: $(BUILD_DIR)/$(TARGET).bin
st-flash write $< 0x8000000
size: $(BUILD_DIR)/$(TARGET).elf
$(SZ) $<
flash: $(BUILD_DIR)/$(TARGET).bin
st-flash write $< 0x8000000
flash-pico: $(BUILD_DIR)/$(TARGET).bin
pico-openocd -f target/stm32f1x.cfg -c "program $< 0x08000000 verify reset exit"
analyze: $(BUILD_DIR)/$(TARGET).elf
python -m elf_size_analyze --rom $<
fonts:
make -C Lib/ufb fonts

@ -62,8 +62,8 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 48K
EEPROM_EMU (rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 16K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 56K
EEPROM_EMU (rx) : ORIGIN = 0x800E000, LENGTH = 8K
}
/* Define output sections */
@ -135,7 +135,7 @@ SECTIONS
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
@ -146,7 +146,7 @@ SECTIONS
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
@ -174,7 +174,7 @@ SECTIONS
. = ALIGN(8);
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ :

Loading…
Cancel
Save