From e4f7946dcbaf1fdb59f910feafd6902d5005bf34 Mon Sep 17 00:00:00 2001 From: "Ben V. Brown" Date: Sun, 2 May 2021 21:22:29 +1000 Subject: [PATCH] WiP on WS2812 Protocol driver --- source/Core/BSP/MHP30/BSP.cpp | 6 +- source/Core/BSP/MHP30/Pins.h | 2 +- source/Core/BSP/MHP30/Setup.c | 638 +++++++++++----------- source/Core/BSP/MHP30/Setup.h | 2 +- source/Core/BSP/MHP30/postRTOS.cpp | 13 +- source/Core/BSP/MHP30/stm32f1xx_hal_msp.c | 21 +- source/Core/BSP/MHP30/stm32f1xx_it.c | 2 +- source/Core/Drivers/WS2812.cpp | 198 +++++++ source/Core/Drivers/WS2812.h | 41 ++ source/Makefile | 2 +- 10 files changed, 596 insertions(+), 329 deletions(-) create mode 100644 source/Core/Drivers/WS2812.cpp create mode 100644 source/Core/Drivers/WS2812.h diff --git a/source/Core/BSP/MHP30/BSP.cpp b/source/Core/BSP/MHP30/BSP.cpp index b8d03c1c..d6a31b8b 100644 --- a/source/Core/BSP/MHP30/BSP.cpp +++ b/source/Core/BSP/MHP30/BSP.cpp @@ -7,6 +7,7 @@ #include "Setup.h" #include "TipThermoModel.h" #include "Utils.h" +#include "WS2812.h" #include "configuration.h" #include "history.hpp" #include "main.hpp" @@ -410,4 +411,7 @@ bool isTipDisconnected() { return tipDisconnected; } -void setStatusLED(const enum StatusLED state) {} +void setStatusLED(const enum StatusLED state) { + WS2812::led_set_color(0, 0xFF, 0, 0); + WS2812::led_update(1); +} diff --git a/source/Core/BSP/MHP30/Pins.h b/source/Core/BSP/MHP30/Pins.h index 4b28f43f..601bd52f 100644 --- a/source/Core/BSP/MHP30/Pins.h +++ b/source/Core/BSP/MHP30/Pins.h @@ -51,6 +51,6 @@ #define PLATE_SENSOR_ADC1_CHANNEL ADC_CHANNEL_5 #define PLATE_SENSOR_ADC2_CHANNEL ADC_CHANNEL_5 -#define WS2812_Pin GPIO_PIN_3 +#define WS2812_Pin GPIO_PIN_8 #define WS2812_GPIO_Port GPIOA #endif /* BSP_MINIWARE_PINS_H_ */ diff --git a/source/Core/BSP/MHP30/Setup.c b/source/Core/BSP/MHP30/Setup.c index e48a85f0..28817182 100644 --- a/source/Core/BSP/MHP30/Setup.c +++ b/source/Core/BSP/MHP30/Setup.c @@ -16,10 +16,10 @@ DMA_HandleTypeDef hdma_i2c1_rx; DMA_HandleTypeDef hdma_i2c1_tx; IWDG_HandleTypeDef hiwdg; -TIM_HandleTypeDef htim1; -DMA_HandleTypeDef hdma_tim1_ch2; -TIM_HandleTypeDef htim2; -TIM_HandleTypeDef htim3; +TIM_HandleTypeDef htim1; +DMA_HandleTypeDef hdma_tim1_ch1; +TIM_HandleTypeDef htim2; +TIM_HandleTypeDef htim3; #define ADC_CHANNELS 4 #define ADC_SAMPLES 16 uint32_t ADCReadings[ADC_SAMPLES * ADC_CHANNELS]; // room for 32 lots of the pair of readings @@ -35,410 +35,422 @@ static void MX_TIM1_Init(void); static void MX_DMA_Init(void); static void MX_GPIO_Init(void); static void MX_ADC2_Init(void); -void Setup_HAL() { - SystemClock_Config(); +void Setup_HAL() { + SystemClock_Config(); - __HAL_AFIO_REMAP_SWJ_NOJTAG(); + __HAL_AFIO_REMAP_SWJ_NOJTAG(); - MX_GPIO_Init(); - MX_DMA_Init(); - MX_I2C1_Init(); - MX_ADC1_Init(); - MX_ADC2_Init(); - MX_TIM3_Init(); - MX_TIM2_Init(); - MX_TIM1_Init(); - MX_IWDG_Init(); - HAL_ADC_Start(&hadc2); - HAL_ADCEx_MultiModeStart_DMA(&hadc1, ADCReadings, - (ADC_SAMPLES * ADC_CHANNELS)); // start DMA of normal readings - // HAL_ADCEx_InjectedStart(&hadc1); // enable injected readings - // HAL_ADCEx_InjectedStart(&hadc2); // enable injected readings + MX_GPIO_Init(); + MX_DMA_Init(); + MX_I2C1_Init(); + MX_ADC1_Init(); + MX_ADC2_Init(); + MX_TIM3_Init(); + MX_TIM2_Init(); + MX_TIM1_Init(); + MX_IWDG_Init(); + HAL_ADC_Start(&hadc2); + HAL_ADCEx_MultiModeStart_DMA(&hadc1, ADCReadings, + (ADC_SAMPLES * ADC_CHANNELS)); // start DMA of normal readings + // HAL_ADCEx_InjectedStart(&hadc1); // enable injected readings + // HAL_ADCEx_InjectedStart(&hadc2); // enable injected readings } // channel 0 -> temperature sensor, 1-> VIN, 2-> tip uint16_t getADC(uint8_t channel) { - uint32_t sum = 0; - for (uint8_t i = 0; i < ADC_SAMPLES; i++) { - uint16_t adc1Sample = ADCReadings[channel + (i * ADC_CHANNELS)]; - uint16_t adc2Sample = ADCReadings[channel + (i * ADC_CHANNELS)] >> 16; + uint32_t sum = 0; + for (uint8_t i = 0; i < ADC_SAMPLES; i++) { + uint16_t adc1Sample = ADCReadings[channel + (i * ADC_CHANNELS)]; + uint16_t adc2Sample = ADCReadings[channel + (i * ADC_CHANNELS)] >> 16; - sum += (adc1Sample + adc2Sample); - } - return sum >> 2; + sum += (adc1Sample + adc2Sample); + } + return sum >> 2; } /** System Clock Configuration */ void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct; - RCC_ClkInitTypeDef RCC_ClkInitStruct; - RCC_PeriphCLKInitTypeDef PeriphClkInit; + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_ClkInitTypeDef RCC_ClkInitStruct; + RCC_PeriphCLKInitTypeDef PeriphClkInit; - /**Initializes the CPU, AHB and APB busses clocks - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = 16; - RCC_OscInitStruct.LSIState = RCC_LSI_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16; // 64MHz - HAL_RCC_OscConfig(&RCC_OscInitStruct); + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI + | RCC_OSCILLATORTYPE_LSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; + RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16; // 64MHz + HAL_RCC_OscConfig(&RCC_OscInitStruct); - /**Initializes the CPU, AHB and APB busses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV16; // TIM - // 2,3,4,5,6,7,12,13,14 - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 64 mhz to some peripherals and adc + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV16; // TIM + // 2,3,4,5,6,7,12,13,14 + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 64 mhz to some peripherals and adc - HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); + HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; - PeriphClkInit.AdcClockSelection = RCC_CFGR_ADCPRE_DIV8; // 6 or 8 are the only non overclocked options - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; + PeriphClkInit.AdcClockSelection = RCC_CFGR_ADCPRE_DIV8; // 6 or 8 are the only non overclocked options + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); - /**Configure the Systick interrupt time - */ - HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); + /**Configure the Systick interrupt time + */ + HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); - /**Configure the Systick - */ - HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); + /**Configure the Systick + */ + HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); - /* SysTick_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0); + /* SysTick_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0); } /* ADC1 init function */ static void MX_ADC1_Init(void) { - ADC_MultiModeTypeDef multimode; + ADC_MultiModeTypeDef multimode; - ADC_ChannelConfTypeDef sConfig; - /**Common config - */ - hadc1.Instance = ADC1; - hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; - hadc1.Init.ContinuousConvMode = ENABLE; - hadc1.Init.DiscontinuousConvMode = DISABLE; - hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; - hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; - hadc1.Init.NbrOfConversion = ADC_CHANNELS; - HAL_ADC_Init(&hadc1); + ADC_ChannelConfTypeDef sConfig; + /**Common config + */ + hadc1.Instance = ADC1; + hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; + hadc1.Init.ContinuousConvMode = ENABLE; + hadc1.Init.DiscontinuousConvMode = DISABLE; + hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc1.Init.NbrOfConversion = ADC_CHANNELS; + HAL_ADC_Init(&hadc1); - /**Configure the ADC multi-mode - */ - multimode.Mode = ADC_DUALMODE_REGSIMULT_INJECSIMULT; - HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode); + /**Configure the ADC multi-mode + */ + multimode.Mode = ADC_DUALMODE_REGSIMULT_INJECSIMULT; + HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode); - /**Configure Regular Channel - */ - sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; + /**Configure Regular Channel + */ + sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; - sConfig.Channel = TMP36_ADC1_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_1; - HAL_ADC_ConfigChannel(&hadc1, &sConfig); + sConfig.Channel = TMP36_ADC1_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_1; + HAL_ADC_ConfigChannel(&hadc1, &sConfig); - /**Configure Regular Channel - */ - sConfig.Channel = VIN_ADC1_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_2; - HAL_ADC_ConfigChannel(&hadc1, &sConfig); + /**Configure Regular Channel + */ + sConfig.Channel = VIN_ADC1_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_2; + HAL_ADC_ConfigChannel(&hadc1, &sConfig); - sConfig.Channel = TIP_TEMP_ADC1_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_3; - HAL_ADC_ConfigChannel(&hadc1, &sConfig); + sConfig.Channel = TIP_TEMP_ADC1_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_3; + HAL_ADC_ConfigChannel(&hadc1, &sConfig); - sConfig.Channel = PLATE_SENSOR_ADC1_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_4; - HAL_ADC_ConfigChannel(&hadc1, &sConfig); + sConfig.Channel = PLATE_SENSOR_ADC1_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_4; + HAL_ADC_ConfigChannel(&hadc1, &sConfig); - SET_BIT(hadc1.Instance->CR1, (ADC_CR1_EOSIE)); // Enable end of Normal - // Run ADC internal calibration - while (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK) - ; + SET_BIT(hadc1.Instance->CR1, (ADC_CR1_EOSIE)); // Enable end of Normal + // Run ADC internal calibration + while (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK) + ; } /* ADC2 init function */ static void MX_ADC2_Init(void) { - ADC_ChannelConfTypeDef sConfig; + ADC_ChannelConfTypeDef sConfig; - /**Common config - */ - hadc2.Instance = ADC2; - hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; - hadc2.Init.ContinuousConvMode = ENABLE; - hadc2.Init.DiscontinuousConvMode = DISABLE; - hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; - hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; - hadc2.Init.NbrOfConversion = ADC_CHANNELS; - HAL_ADC_Init(&hadc2); - sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; + /**Common config + */ + hadc2.Instance = ADC2; + hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; + hadc2.Init.ContinuousConvMode = ENABLE; + hadc2.Init.DiscontinuousConvMode = DISABLE; + hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc2.Init.NbrOfConversion = ADC_CHANNELS; + HAL_ADC_Init(&hadc2); + sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; - /**Configure Regular Channel - */ - sConfig.Channel = TMP36_ADC2_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_1; - HAL_ADC_ConfigChannel(&hadc2, &sConfig); + /**Configure Regular Channel + */ + sConfig.Channel = TMP36_ADC2_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_1; + HAL_ADC_ConfigChannel(&hadc2, &sConfig); - sConfig.Channel = VIN_ADC2_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_2; - HAL_ADC_ConfigChannel(&hadc2, &sConfig); - sConfig.Channel = TIP_TEMP_ADC1_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_3; - HAL_ADC_ConfigChannel(&hadc2, &sConfig); - sConfig.Channel = PLATE_SENSOR_ADC2_CHANNEL; - sConfig.Rank = ADC_REGULAR_RANK_4; - HAL_ADC_ConfigChannel(&hadc2, &sConfig); + sConfig.Channel = VIN_ADC2_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_2; + HAL_ADC_ConfigChannel(&hadc2, &sConfig); + sConfig.Channel = TIP_TEMP_ADC1_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_3; + HAL_ADC_ConfigChannel(&hadc2, &sConfig); + sConfig.Channel = PLATE_SENSOR_ADC2_CHANNEL; + sConfig.Rank = ADC_REGULAR_RANK_4; + HAL_ADC_ConfigChannel(&hadc2, &sConfig); - // Run ADC internal calibration - while (HAL_ADCEx_Calibration_Start(&hadc2) != HAL_OK) - ; + // Run ADC internal calibration + while (HAL_ADCEx_Calibration_Start(&hadc2) != HAL_OK) + ; } /* I2C1 init function */ static void MX_I2C1_Init(void) { - hi2c1.Instance = I2C1; - hi2c1.Init.ClockSpeed = 300000; - hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; - hi2c1.Init.OwnAddress1 = 0; - hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; - hi2c1.Init.OwnAddress2 = 0; - hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; - hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; - HAL_I2C_Init(&hi2c1); + hi2c1.Instance = I2C1; + hi2c1.Init.ClockSpeed = 300000; + hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; + hi2c1.Init.OwnAddress1 = 0; + hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c1.Init.OwnAddress2 = 0; + hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + HAL_I2C_Init(&hi2c1); } /* IWDG init function */ static void MX_IWDG_Init(void) { - hiwdg.Instance = IWDG; - hiwdg.Init.Prescaler = IWDG_PRESCALER_256; - hiwdg.Init.Reload = 100; + hiwdg.Instance = IWDG; + hiwdg.Init.Prescaler = IWDG_PRESCALER_256; + hiwdg.Init.Reload = 100; #ifndef SWD_ENABLE - HAL_IWDG_Init(&hiwdg); + HAL_IWDG_Init(&hiwdg); #endif } /* TIM1 init function */ void MX_TIM1_Init(void) { - /* USER CODE BEGIN TIM1_Init 0 */ + /* USER CODE BEGIN TIM1_Init 0 */ - /* USER CODE END TIM1_Init 0 */ + /* USER CODE END TIM1_Init 0 */ - TIM_ClockConfigTypeDef sClockSourceConfig = {0}; - TIM_MasterConfigTypeDef sMasterConfig = {0}; - TIM_OC_InitTypeDef sConfigOC = {0}; - TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + TIM_ClockConfigTypeDef sClockSourceConfig = { 0 }; + TIM_MasterConfigTypeDef sMasterConfig = { 0 }; + TIM_OC_InitTypeDef sConfigOC = { 0 }; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = { 0 }; - /* USER CODE BEGIN TIM1_Init 1 */ + /* USER CODE BEGIN TIM1_Init 1 */ - /* USER CODE END TIM1_Init 1 */ - htim1.Instance = TIM1; - htim1.Init.Prescaler = 0; - htim1.Init.CounterMode = TIM_COUNTERMODE_UP; - htim1.Init.Period = 104; - htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - htim1.Init.RepetitionCounter = 0; - htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - if (HAL_TIM_Base_Init(&htim1) != HAL_OK) {} - sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; - if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) {} - if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) {} - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) {} - sConfigOC.OCMode = TIM_OCMODE_PWM1; - sConfigOC.Pulse = 0; - sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; - sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; - sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; - sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; - sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; - if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) {} - sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; - sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; - sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; - sBreakDeadTimeConfig.DeadTime = 0; - sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; - sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; - sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; - if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) {} - /* USER CODE BEGIN TIM1_Init 2 */ + /* USER CODE END TIM1_Init 1 */ + htim1.Instance = TIM1; + htim1.Init.Prescaler = 0; + htim1.Init.CounterMode = TIM_COUNTERMODE_UP; + htim1.Init.Period = 40; + htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim1.Init.RepetitionCounter = 0; + htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + HAL_TIM_Base_Init(&htim1); - /* USER CODE END TIM1_Init 2 */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - GPIO_InitTypeDef GPIO_InitStruct; - /**TIM1 GPIO Configuration - PA9 ------> TIM1_CH2 - */ - GPIO_InitStruct.Pin = WS2812_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(WS2812_GPIO_Port, &GPIO_InitStruct); + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig); + + HAL_TIM_PWM_Init(&htim1); + + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig); + + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); + + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitTypeDef GPIO_InitStruct; + /**TIM1 GPIO Configuration + PA8 ------> TIM1_CH1 + */ + GPIO_InitStruct.Pin = WS2812_Pin; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(WS2812_GPIO_Port, &GPIO_InitStruct); + __HAL_AFIO_REMAP_TIM1_DISABLE(); } /* TIM3 init function */ static void MX_TIM3_Init(void) { - TIM_ClockConfigTypeDef sClockSourceConfig; - TIM_MasterConfigTypeDef sMasterConfig; - TIM_OC_InitTypeDef sConfigOC; + TIM_ClockConfigTypeDef sClockSourceConfig; + TIM_MasterConfigTypeDef sMasterConfig; + TIM_OC_InitTypeDef sConfigOC; - htim3.Instance = TIM3; - htim3.Init.Prescaler = 1; - htim3.Init.CounterMode = TIM_COUNTERMODE_UP; - htim3.Init.Period = 255; // - htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 4mhz before div - htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; // Preload the ARR register (though we dont use this) - HAL_TIM_Base_Init(&htim3); + htim3.Instance = TIM3; + htim3.Init.Prescaler = 1; + htim3.Init.CounterMode = TIM_COUNTERMODE_UP; + htim3.Init.Period = 255; // + htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 4mhz before div + htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; // Preload the ARR register (though we dont use this) + HAL_TIM_Base_Init(&htim3); - sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; - HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig); + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig); - HAL_TIM_PWM_Init(&htim3); + HAL_TIM_PWM_Init(&htim3); - HAL_TIM_OC_Init(&htim3); + HAL_TIM_OC_Init(&htim3); - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig); + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig); - sConfigOC.OCMode = TIM_OCMODE_PWM1; - sConfigOC.Pulse = 0; // Output control - sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; - sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; - HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, PWM_Out_CHANNEL); - // TODO need to do buzzer - GPIO_InitTypeDef GPIO_InitStruct; + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; // Output control + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; + HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, PWM_Out_CHANNEL); + // TODO need to do buzzer + GPIO_InitTypeDef GPIO_InitStruct; - /**TIM3 GPIO Configuration - PWM_Out_Pin ------> TIM3_CH1 - */ - GPIO_InitStruct.Pin = PWM_Out_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // We would like sharp rising edges - HAL_GPIO_Init(PWM_Out_GPIO_Port, &GPIO_InitStruct); - HAL_TIM_PWM_Start(&htim3, PWM_Out_CHANNEL); + /**TIM3 GPIO Configuration + PWM_Out_Pin ------> TIM3_CH1 + */ + GPIO_InitStruct.Pin = PWM_Out_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // We would like sharp rising edges + HAL_GPIO_Init(PWM_Out_GPIO_Port, &GPIO_InitStruct); + HAL_TIM_PWM_Start(&htim3, PWM_Out_CHANNEL); } /* TIM3 init function */ static void MX_TIM2_Init(void) { - TIM_ClockConfigTypeDef sClockSourceConfig; - TIM_MasterConfigTypeDef sMasterConfig; - TIM_OC_InitTypeDef sConfigOC; + TIM_ClockConfigTypeDef sClockSourceConfig; + TIM_MasterConfigTypeDef sMasterConfig; + TIM_OC_InitTypeDef sConfigOC; - htim2.Instance = TIM2; - htim2.Init.Prescaler = 200; // 2 MHz timer clock/2000 = 1 kHz tick rate + htim2.Instance = TIM2; + htim2.Init.Prescaler = 200; // 2 MHz timer clock/2000 = 1 kHz tick rate - // pwm out is 10k from tim3, we want to run our PWM at around 10hz or slower on the output stage - // These values give a rate of around 3.5 Hz for "fast" mode and 1.84 Hz for "slow" - htim2.Init.CounterMode = TIM_COUNTERMODE_UP; - // dummy value, will be reconfigured by BSPInit() - htim2.Init.Period = 10; - htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 8 MHz (x2 APB1) before divide - htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - htim2.Init.RepetitionCounter = 0; - HAL_TIM_Base_Init(&htim2); + // pwm out is 10k from tim3, we want to run our PWM at around 10hz or slower on the output stage + // These values give a rate of around 3.5 Hz for "fast" mode and 1.84 Hz for "slow" + htim2.Init.CounterMode = TIM_COUNTERMODE_UP; + // dummy value, will be reconfigured by BSPInit() + htim2.Init.Period = 10; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 8 MHz (x2 APB1) before divide + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + htim2.Init.RepetitionCounter = 0; + HAL_TIM_Base_Init(&htim2); - sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; - HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig); + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig); - HAL_TIM_PWM_Init(&htim2); + HAL_TIM_PWM_Init(&htim2); - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig); + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig); - sConfigOC.OCMode = TIM_OCMODE_PWM1; - // dummy value, will be reconfigured by BSPInit() in the BSP.cpp - sConfigOC.Pulse = 5; - sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; - sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; - HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4); - GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = HEAT_EN_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // We would like sharp rising edges - HAL_GPIO_Init(HEAT_EN_GPIO_Port, &GPIO_InitStruct); - HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); + sConfigOC.OCMode = TIM_OCMODE_PWM1; + // dummy value, will be reconfigured by BSPInit() in the BSP.cpp + sConfigOC.Pulse = 5; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; + HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4); + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = HEAT_EN_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // We would like sharp rising edges + HAL_GPIO_Init(HEAT_EN_GPIO_Port, &GPIO_InitStruct); + HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { - /* DMA controller clock enable */ - __HAL_RCC_DMA1_CLK_ENABLE(); + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); - /* DMA interrupt init */ - /* DMA1_Channel1_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 10, 0); - HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); - /* DMA1_Channel1_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 6, 0); // DMA 1 ch3 is used from TIM CH2 for WS2812 - HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); - /* DMA1_Channel6_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); - /* DMA1_Channel7_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn); + /* DMA interrupt init */ + /* DMA1_Channel1_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 10, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); + /* DMA1_Channel1_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 2, 0); // DMA 1 ch2 is used from TIM CH1 for WS2812 + HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn); + /* DMA1_Channel6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn); + /* DMA1_Channel7_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn); } static void MX_GPIO_Init(void) { - GPIO_InitTypeDef GPIO_InitStruct; - memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); + GPIO_InitTypeDef GPIO_InitStruct; + memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOD_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); - /*Configure GPIO pin Output Level */ - HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - /*Configure GPIO pins : PD0 PD1 */ - GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - /*Configure peripheral I/O remapping */ - __HAL_AFIO_REMAP_PD01_ENABLE(); - //^ remap XTAL so that pins used + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + /*Configure GPIO pins : PD0 PD1 */ + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + /*Configure peripheral I/O remapping */ + __HAL_AFIO_REMAP_PD01_ENABLE(); + //^ remap XTAL so that pins used - /* - * Configure All pins as analog by default - */ - GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_15; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 - | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + /* + * Configure All pins as analog by default + */ + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 + | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 + | GPIO_PIN_10 | GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 + | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 + | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 + | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - /*Configure GPIO pins : KEY_B_Pin KEY_A_Pin */ - GPIO_InitStruct.Pin = KEY_B_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_PULLUP; - HAL_GPIO_Init(KEY_B_GPIO_Port, &GPIO_InitStruct); - GPIO_InitStruct.Pin = KEY_A_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_PULLUP; - HAL_GPIO_Init(KEY_A_GPIO_Port, &GPIO_InitStruct); + /*Configure GPIO pins : KEY_B_Pin KEY_A_Pin */ + GPIO_InitStruct.Pin = KEY_B_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(KEY_B_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Pin = KEY_A_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + HAL_GPIO_Init(KEY_A_GPIO_Port, &GPIO_InitStruct); - /*Configure GPIO pin : OLED_RESET_Pin */ - GPIO_InitStruct.Pin = OLED_RESET_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(OLED_RESET_GPIO_Port, &GPIO_InitStruct); - HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); + /*Configure GPIO pin : OLED_RESET_Pin */ + GPIO_InitStruct.Pin = OLED_RESET_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(OLED_RESET_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); + + // Pull down LCD reset + HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); + HAL_Delay(30); + HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET); - // Pull down LCD reset - HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_RESET); - HAL_Delay(30); - HAL_GPIO_WritePin(OLED_RESET_GPIO_Port, OLED_RESET_Pin, GPIO_PIN_SET); } #ifdef USE_FULL_ASSERT diff --git a/source/Core/BSP/MHP30/Setup.h b/source/Core/BSP/MHP30/Setup.h index 4628caf1..045b951c 100644 --- a/source/Core/BSP/MHP30/Setup.h +++ b/source/Core/BSP/MHP30/Setup.h @@ -25,7 +25,7 @@ extern I2C_HandleTypeDef hi2c1; extern IWDG_HandleTypeDef hiwdg; extern TIM_HandleTypeDef htim1; -extern DMA_HandleTypeDef hdma_tim1_ch2; +extern DMA_HandleTypeDef hdma_tim1_ch1; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; void Setup_HAL(); diff --git a/source/Core/BSP/MHP30/postRTOS.cpp b/source/Core/BSP/MHP30/postRTOS.cpp index 2daab8b6..0b862aff 100644 --- a/source/Core/BSP/MHP30/postRTOS.cpp +++ b/source/Core/BSP/MHP30/postRTOS.cpp @@ -3,6 +3,7 @@ #include "I2C_Wrapper.hpp" #include "QC3.h" #include "Settings.h" +#include "WS2812.h" #include "cmsis_os.h" #include "fusbpd.h" #include "main.hpp" @@ -11,4 +12,14 @@ #include "task.h" // Initialisation to be performed with scheduler active -void postRToSInit() {} +void postRToSInit() { + WS2812::init(); + WS2812::led_set_color(0, 0xAA, 0x55, 0x00); + while (true) { +// osDelay(1); +// WS2812::led_set_color(0, 0xFF, 0xFF, 0xFF); +// WS2812::led_update(1); + osDelay(10); + WS2812::led_update(1); + } +} diff --git a/source/Core/BSP/MHP30/stm32f1xx_hal_msp.c b/source/Core/BSP/MHP30/stm32f1xx_hal_msp.c index b53f5404..e2c57d11 100644 --- a/source/Core/BSP/MHP30/stm32f1xx_hal_msp.c +++ b/source/Core/BSP/MHP30/stm32f1xx_hal_msp.c @@ -128,16 +128,17 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base) { if (htim_base->Instance == TIM1) { __HAL_RCC_TIM1_CLK_ENABLE(); - hdma_tim1_ch2.Instance = DMA1_Channel3; - hdma_tim1_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_tim1_ch2.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_tim1_ch2.Init.MemInc = DMA_MINC_ENABLE; - hdma_tim1_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - hdma_tim1_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; - hdma_tim1_ch2.Init.Mode = DMA_CIRCULAR; - hdma_tim1_ch2.Init.Priority = DMA_PRIORITY_LOW; - if (HAL_DMA_Init(&hdma_tim1_ch2) != HAL_OK) {} - __HAL_LINKDMA(htim_base, hdma[TIM_DMA_ID_CC2], hdma_tim1_ch2); + __HAL_RCC_DMA1_CLK_ENABLE(); + hdma_tim1_ch1.Instance = DMA1_Channel2; + hdma_tim1_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tim1_ch1.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tim1_ch1.Init.MemInc = DMA_MINC_ENABLE; + hdma_tim1_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_tim1_ch1.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_tim1_ch1.Init.Mode = DMA_CIRCULAR; + hdma_tim1_ch1.Init.Priority = DMA_PRIORITY_VERY_HIGH; + HAL_DMA_Init(&hdma_tim1_ch1); + __HAL_LINKDMA(htim_base, hdma[TIM_DMA_ID_CC1], hdma_tim1_ch1); } else if (htim_base->Instance == TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); } else if (htim_base->Instance == TIM2) { diff --git a/source/Core/BSP/MHP30/stm32f1xx_it.c b/source/Core/BSP/MHP30/stm32f1xx_it.c index 17388cff..40c327d1 100644 --- a/source/Core/BSP/MHP30/stm32f1xx_it.c +++ b/source/Core/BSP/MHP30/stm32f1xx_it.c @@ -49,7 +49,7 @@ void TIM4_IRQHandler(void) { HAL_TIM_IRQHandler(&htim4); } void I2C1_EV_IRQHandler(void) { HAL_I2C_EV_IRQHandler(&hi2c1); } void I2C1_ER_IRQHandler(void) { HAL_I2C_ER_IRQHandler(&hi2c1); } -void DMA1_Channel3_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_tim1_ch2); } +void DMA1_Channel2_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_tim1_ch1); } void DMA1_Channel6_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_i2c1_tx); } void DMA1_Channel7_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_i2c1_rx); } diff --git a/source/Core/Drivers/WS2812.cpp b/source/Core/Drivers/WS2812.cpp new file mode 100644 index 00000000..fce3c193 --- /dev/null +++ b/source/Core/Drivers/WS2812.cpp @@ -0,0 +1,198 @@ +/* + * WS2812.cpp + * + * Created on: 2 May 2021 + * Author: Ralim + */ + +#include "FreeRTOS.h" +#include "task.h" +#include +#include +uint8_t WS2812::leds_colors[WS2812_LED_CHANNEL_COUNT * WS2812_LED_COUNT]; +volatile uint16_t WS2812::tmp_led_data[2 * WS2812_RAW_BYTES_PER_LED]; +volatile uint8_t WS2812::is_reset_pulse; /*!< Status if we are sending reset pulse or led data */ +volatile uint8_t WS2812::is_updating; /*!< Is updating in progress? */ +volatile uint32_t WS2812::current_led; /*!< Current LED number we are sending */ + +void WS2812::init(void) { + memset(leds_colors, 0, sizeof(leds_colors)); + hdma_tim1_ch1.XferHalfCpltCallback = DMAHalfComplete; + hdma_tim1_ch1.XferCpltCallback = DMAComplete; + htim1.Instance->CCR1 = htim1.Instance->ARR / 2 - 1; + htim1.Instance->DIER |= TIM_DIER_CC1DE; +} + +uint8_t WS2812::led_update(uint8_t block) { + if (is_updating) { /* Check if update in progress already */ + return 0; + } + is_updating = 1; /* We are now updating */ + + led_start_reset_pulse(1); /* Start reset pulse */ + if (block) { + while (!led_is_update_finished()) { + vTaskDelay(1); + }; /* Wait to finish */ + } + return 1; +} + +void WS2812::led_set_color(size_t index, uint8_t r, uint8_t g, uint8_t b) { + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 0] = r; + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 1] = g; + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 2] = b; +} + +void WS2812::led_set_color_all(uint8_t r, uint8_t g, uint8_t b) { + for (int index = 0; index < WS2812_LED_COUNT; index++) { + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 0] = r; + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 1] = g; + leds_colors[index * WS2812_LED_CHANNEL_COUNT + 2] = b; + } +} + +uint8_t WS2812::led_is_update_finished(void) { + return !is_updating; +} + +void WS2812::led_start_reset_pulse(uint8_t num) { + is_reset_pulse = num; /* Set reset pulse flag */ + + memset((void*)tmp_led_data, 0, sizeof(tmp_led_data)); /* Set all bytes to 0 to achieve 50us pulse */ + + if (num == 1) { + tmp_led_data[0] = htim1.Instance->ARR / 2; // start with half width pulse + } + + /* Set DMA to normal mode, set memory to beginning of data and length to 40 elements */ + /* 800kHz PWM x 40 samples = ~50us pulse low */ + hdma_tim1_ch1.Instance->CCR &= (~DMA_CCR_CIRC); // clear circular flag -> normal mode + hdma_tim1_ch1.State = HAL_DMA_STATE_READY; + HAL_DMA_Start_IT(&hdma_tim1_ch1, (uint32_t) tmp_led_data, + (uint32_t) &htim1.Instance->CCR1, 40); + HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); +} + +void WS2812::DMAHalfComplete(DMA_HandleTypeDef *hdma) { + led_update_sequence(0); +} + +void WS2812::DMAComplete(DMA_HandleTypeDef *hdma) { + led_update_sequence(1); +} + +void WS2812::led_update_sequence(uint8_t tc) { + tc = !!tc; /* Convert to 1 or 0 value only */ + + /* Check for reset pulse at the end of PWM stream */ + if (is_reset_pulse == 2) { /* Check for reset pulse at the end */ + HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); + HAL_DMA_Abort(&hdma_tim1_ch1); + is_updating = 0; /* We are not updating anymore */ + return; + } + + /* Check for reset pulse on beginning of PWM stream */ + if (is_reset_pulse == 1) { /* Check if we finished with reset pulse */ + /* + * When reset pulse is active, we have to wait full DMA response, + * before we can start modifying array which is shared with DMA and PWM + */ + if (!tc) { /* We must wait for transfer complete */ + return; /* Return and wait to finish */ + } + + /* Disable timer output and disable DMA stream */ + HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); + HAL_DMA_Abort(&hdma_tim1_ch1); + + is_reset_pulse = 0; /* Not in reset pulse anymore */ + current_led = 0; /* Reset current led */ + } else { + /* + * When we are not in reset mode, + * go to next led and process data for it + */ + current_led++; /* Go to next LED */ + } + + /* + * This part is used to prepare data for "next" led, + * for which update will start once current transfer stops in circular mode + */ + if (current_led < WS2812_LED_COUNT) { + /* + * If we are preparing data for first time (current_led == 0) + * or if there was no TC event (it was HT): + * + * - Prepare first part of array, because either there is no transfer + * or second part (from HT to TC) is now in process for PWM transfer + * + * In other case (TC = 1) + */ + if (current_led == 0 || !tc) { + led_fill_led_pwm_data(current_led, &tmp_led_data[0]); + } else { + led_fill_led_pwm_data(current_led, + &tmp_led_data[WS2812_RAW_BYTES_PER_LED]); + } + + /* + * If we are preparing first led (current_led = 0), then: + * + * - We setup first part of array for first led, + * - We have to prepare second part for second led to have one led prepared in advance + * - Set DMA to circular mode and start the transfer + PWM output + */ + if (current_led == 0) { + + current_led++; /* Go to next LED */ + led_fill_led_pwm_data(current_led, + &tmp_led_data[WS2812_RAW_BYTES_PER_LED]); /* Prepare second LED too */ + hdma_tim1_ch1.Instance->CCR |= (DMA_CCR_CIRC); // set circular flag for circular mode + hdma_tim1_ch1.State = HAL_DMA_STATE_READY; + HAL_DMA_Start_IT(&hdma_tim1_ch1, (uint32_t) tmp_led_data, + (uint32_t) &htim1.Instance->CCR1, + 2 * WS2812_RAW_BYTES_PER_LED); + HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); + } + + /* + * When we reached all leds, we have to wait to transmit data for all leds before we can disable DMA and PWM: + * + * - If TC event is enabled and we have EVEN number of LEDS (2, 4, 6, ...) + * - If HT event is enabled and we have ODD number of LEDS (1, 3, 5, ...) + */ + } else if ((!tc && (WS2812_LED_COUNT & 0x01)) + || (tc && !(WS2812_LED_COUNT & 0x01))) { + HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); + HAL_DMA_Abort(&hdma_tim1_ch1); + + /* It is time to send final reset pulse, 50us at least */ + led_start_reset_pulse(2); /* Start reset pulse at the end */ + } +} + +void WS2812::led_fill_led_pwm_data(size_t ledx, volatile uint16_t *ptr) { + size_t i; + uint16_t OnOffValues[] = { 2* htim1.Instance->ARR / 3, + (4 * htim1.Instance->ARR) / 3 }; + + if (ledx < WS2812_LED_COUNT) { + for (i = 0; i < 8; i++) { + //Also unmux RGB -> GRB in the index order here + ptr[i] = + (leds_colors[WS2812_LED_CHANNEL_COUNT * ledx + 1] + & (1 << (7 - i))) ? OnOffValues[1] : OnOffValues[0]; + ptr[8 + i] = + (leds_colors[WS2812_LED_CHANNEL_COUNT * ledx + 0] + & (1 << (7 - i))) ? OnOffValues[1] : OnOffValues[0]; + ptr[16 + i] = + (leds_colors[WS2812_LED_CHANNEL_COUNT * ledx + 2] + & (1 << (7 - i))) ? OnOffValues[1] : OnOffValues[0]; + } + } else { + //Fill with zero? + } +} diff --git a/source/Core/Drivers/WS2812.h b/source/Core/Drivers/WS2812.h new file mode 100644 index 00000000..e43de1e3 --- /dev/null +++ b/source/Core/Drivers/WS2812.h @@ -0,0 +1,41 @@ +/* + * WS2812.h + * + * Created on: 2 May 2021 + * Author: Ralim + */ +#include "Setup.h" +#include +#include + +#ifndef CORE_DRIVERS_WS2812_H_ +#define CORE_DRIVERS_WS2812_H_ +#ifndef WS2812_LED_COUNT +#define WS2812_LED_COUNT 4 +#endif +#ifndef WS2812_LED_CHANNEL_COUNT +#define WS2812_LED_CHANNEL_COUNT 3 +#endif +#define WS2812_RAW_BYTES_PER_LED (WS2812_LED_CHANNEL_COUNT * 8) +class WS2812 { +public: + static void init(void); + static uint8_t led_update(uint8_t block); + static void led_set_color(size_t index, uint8_t r, uint8_t g, uint8_t b); + static void led_set_color_all(uint8_t r, uint8_t g, uint8_t b); + +private: + static uint8_t led_is_update_finished(void); + static void led_start_reset_pulse(uint8_t num); + static void DMAHalfComplete(DMA_HandleTypeDef *hdma); + static void DMAComplete(DMA_HandleTypeDef *hdma); + static void led_update_sequence(uint8_t tc); + static void led_fill_led_pwm_data(size_t ledx, volatile uint16_t *ptr); + static uint8_t leds_colors[WS2812_LED_CHANNEL_COUNT * WS2812_LED_COUNT]; + static volatile uint16_t tmp_led_data[2 * WS2812_RAW_BYTES_PER_LED]; + static volatile uint8_t is_reset_pulse; /*!< Status if we are sending reset pulse or led data */ + static volatile uint8_t is_updating; /*!< Is updating in progress? */ + static volatile uint32_t current_led; /*!< Current LED number we are sending */ +}; + +#endif /* CORE_DRIVERS_WS2812_H_ */ diff --git a/source/Makefile b/source/Makefile index f6a261c7..4c436f3c 100644 --- a/source/Makefile +++ b/source/Makefile @@ -127,7 +127,7 @@ CPUFLAGS= -mcpu=cortex-m3 \ -mthumb \ -mfloat-abi=soft flash_size=128k -bootldr_size=0x0000 +bootldr_size=0x8000 endif ifeq ($(model),$(ALL_PINE_MODELS)) $(info Building for Pine64 )