2023-08-03 10:59 AM
Greetings,
I have been working with the STM32F407ZG and a KnobG Click from MikroElectronica. I read the datasheet for the PCA9956B and have managed to address the device successfully at the address of 0x70. Now then according to the usage I have seen in the example code (which is severely abstracted and references heavily several library documents), it seems like they set all the LED outputs to full gain and then use a switch case (which seems to somehow default to 1) and all LED lights glow brightly. I have tested their code on my hardware so I know that it works. However, due to a lack of understanding the data sheet I have not succeeded in making that happen yet. I have however, managed to get the first LED to come on as have directly addressed that register (see below code snippet).
void KNOB_LED1_On(void){
uint8_t data[2];
data[0] = 0x0A;
data[1] = 0x10;
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
}
Question 1: Why does my fade function appear to work in a saw tooth manner? I wrote the code trying to get it to fade in and out smoothly. Instead it just climbs to full brightness and then goes off and starts over.
void KNOB_LED1_Fade(void){
uint8_t data[2];
data[0] = 0x0A; // The LED control register address or whatever the specific command is for your LED
for(uint8_t i = 0; i <= 0xFF; i++) { // Fading in
data[1] = i; // Set brightness
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
HAL_Delay(10); // Around 4ms delay for the fade in to take half a second
}
for(int i = 0xFF; i >= 0; i--) { // Fading out
data[1] = i; // Set brightness
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
HAL_Delay(10); // Around 4ms delay for the fade out to take half a second
}
}
Question 2: I put the above code snippet in the initialization portion of the code before the loop. Why is it that the LED continues to fade? I would expect that it would have only occurred once.
Question 3: With my STLINKv3 in hand, what section of the debugger perspective should I be looking for to ascertain why the loops continue to happen?
Solved! Go to Solution.
2023-08-03 06:30 PM
Hello again
Your fading in loop comparasion fails and execution stays there forever because of i<=0xff and uint8_t type. Use uint16 type for example.
Br J.T
2023-08-03 01:12 PM - edited 2023-08-03 01:12 PM
Debug your board, set a breakpoint or hit pause during execution to see where it's at. Step through and verify behavior is as desired. Likely the code as written doesn't do what you think it does. Consider showing the relevant calls to KNOB_LED1_Fade and surrounding code context here.
The code that you shared seems fine. The problem is likely outside of those functions.
2023-08-03 01:19 PM
You know... I went into debug which I haven't quite fully learned yet. It seems that it get's stuck looping in the fade in portion of that function...
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @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 "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define KNOB_ADDR 0x70 << 1
#define GAIN_REG 0x40
#define GAIN_VAL 0xFF
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
void KNOB_Init(void);
void KNOB_DEF_Config(void);
void KNOB_ALL_On(void);
void KNOB_LED1_On(void);
void KNOB_LED1_Fade(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
KNOB_Init();
KNOB_DEF_Config();
KNOB_ALL_On();
// KNOB_LED1_Fade();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(USR_LD4_GPIO_Port, USR_LD4_Pin);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses 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_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief I2C1 Initialization Function
* @PAram None
* @retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
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;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
/**
* @brief SPI1 Initialization Function
* @PAram None
* @retval None
*/
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @PAram None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @PAram None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, USR_LD2_Pin|USR_LD3_Pin|USR_LD4_Pin|USR_LD5_Pin
|MB1_RST_Pin|USR_LD0_Pin|USR_LD1_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(MB1_PWM_GPIO_Port, MB1_PWM_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : USR_LD2_Pin USR_LD3_Pin USR_LD4_Pin USR_LD5_Pin
USR_LD0_Pin USR_LD1_Pin */
GPIO_InitStruct.Pin = USR_LD2_Pin|USR_LD3_Pin|USR_LD4_Pin|USR_LD5_Pin
|USR_LD0_Pin|USR_LD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pins : MB1_AN_Pin MB1_CS_Pin */
GPIO_InitStruct.Pin = MB1_AN_Pin|MB1_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : MB1_RST_Pin */
GPIO_InitStruct.Pin = MB1_RST_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MB1_RST_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : MB1_PWM_Pin */
GPIO_InitStruct.Pin = MB1_PWM_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MB1_PWM_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : MB1_INT_Pin */
GPIO_InitStruct.Pin = MB1_INT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(MB1_INT_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
void KNOB_Init(void){
HAL_GPIO_WritePin(MB1_RST_GPIO_Port, MB1_RST_Pin, RESET); // Pull the MB1_RST Low
HAL_Delay(10); // Delay minimum 10ms
HAL_GPIO_WritePin(MB1_RST_GPIO_Port, MB1_RST_Pin, SET); // Set MB1_RST HIGH
HAL_Delay(300);
HAL_StatusTypeDef result;
result = HAL_I2C_IsDeviceReady(&hi2c1, KNOB_ADDR, 100, HAL_MAX_DELAY);
if(result != HAL_OK){
HAL_GPIO_WritePin(USR_LD0_GPIO_Port, USR_LD0_Pin, SET);
} else {
HAL_GPIO_WritePin(USR_LD1_GPIO_Port, USR_LD1_Pin, SET);
}
}
void KNOB_DEF_Config(void){
HAL_GPIO_WritePin(MB1_PWM_GPIO_Port, MB1_PWM_Pin, 0x01);
HAL_Delay(1000);
HAL_GPIO_WritePin(MB1_PWM_GPIO_Port, MB1_PWM_Pin, 0x00);
HAL_Delay(1000);
uint8_t data[2];
data[0] = GAIN_REG;
data[1] = GAIN_VAL;
HAL_StatusTypeDef result2;
result2 = HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
if (result2 != HAL_OK){
HAL_GPIO_WritePin(USR_LD2_GPIO_Port, USR_LD2_Pin, SET);
} else {
HAL_GPIO_WritePin(USR_LD3_GPIO_Port, USR_LD3_Pin, SET);
}
}
void KNOB_ALL_On(void){
uint8_t data[2];
data[0] = 0x30;
data[1] = 0xFF;
HAL_StatusTypeDef result1;
result1 = HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
if (result1 != HAL_OK){
HAL_GPIO_WritePin(USR_LD3_GPIO_Port, USR_LD4_Pin, SET);
} else {
HAL_GPIO_WritePin(USR_LD3_GPIO_Port, USR_LD5_Pin, SET);
}
}
void KNOB_LED1_On(void){
uint8_t data[2];
data[0] = 0x0A;
data[1] = 0x10;
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
}
void KNOB_LED1_Fade(void){
uint8_t data[2];
data[0] = 0x0A; // The LED control register address or whatever the specific command is for your LED
for(uint8_t i = 0; i <= 0xFF; i++) { // Fading in
data[1] = i; // Set brightness
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
HAL_Delay(10); // Around 4ms delay for the fade in to take half a second
}
for(int i = 0xFF; i >= 0; i--) { // Fading out
data[1] = i; // Set brightness
HAL_I2C_Master_Transmit(&hi2c1, KNOB_ADDR, data, 2, HAL_MAX_DELAY);
HAL_Delay(100); // Around 4ms delay for the fade out to take half a second
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
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();
while (1)
{
}
/* 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.
* @PAram file: pointer to the source file name
* @PAram line: assert_param error line source number
* @retval None
*/
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 */
}
#endif /* USE_FULL_ASSERT */
2023-08-03 06:30 PM
Hello again
Your fading in loop comparasion fails and execution stays there forever because of i<=0xff and uint8_t type. Use uint16 type for example.
Br J.T
2023-08-03 07:12 PM
@JTP1 thanks for the hint!
While I still don't understand why exactly... I change both portions of the functions fade in and fade out to just plain old int types and the code works. When I go into debug mode, the value for int i in my watch expressions is actually populating now. Is there a way to step each iteration of the loop? I can step into it but I don't see an option to keep cycling through the loop.
2023-08-03 10:13 PM - edited 2023-08-03 10:16 PM
Good morning
With unsigned 8 bit, the value range is 0 - 0xff (0 - 255). In your comparasion value of i should be bigger than 0xff -> variable rolls over back to zero and loop continues forever. You may think fact, that 2^8 is 256, but this exponent gives amount of different bit patterns and range 0 - 255 has that 256 different bit pattern.
If you want to use 8 bit variable, use do - while instead of for. With that you get all values evaluated because the comparasion is after the loop code.
Pressing F5 (Step into) steps you thru all loop iterations. You can set the breakpoint just before loop so execution stops there.
Hope this helps!
Br J.T