Featured

Ambient Light Sensor Controller Software

Ambient Light Sensor Controller Software

Please read Liability Disclaimer and License Agreement CAREFULLY

To check the hardware associated with this software, please read the article Ambient light with APA102 and MQTT

In the main.c we include the library for TCS3471 with #include "TCS3471.h", then we add the variable's for the interrupts

extern volatile uint8_t newGain;
volatile uint8_t S1_READY, S2_READY;

Please note the they have to be also added in main.h

extern volatile uint8_t S1_READY, S2_READY;

Next, we start the initialization of the MCU based on the configuration we have set up in .ioc file

In MX_GPIO_Init(); we have to set up the interrupt pin of the sensors, this way we know exactly when to red the sensors

void MX_GPIO_Init(void){
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOF_CLK_ENABLE();
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	/*Configure GPIO pin : PtPin */
	GPIO_InitStruct.Pin = INT2_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(INT2_GPIO_Port, &GPIO_InitStruct);
	/*Configure GPIO pin : PtPin */
	GPIO_InitStruct.Pin = INT1_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(INT1_GPIO_Port, &GPIO_InitStruct);
	/* EXTI interrupt init*/
	HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}

In the same time we need a interrupt handler, a function that is called when the interrupt is triggered.

This function is found in stm32f3xx_it.c

//The variables first
extern volatile uint8_t S1_READY, S2_READY;

void EXTI9_5_IRQHandler(void){
	/* USER CODE BEGIN EXTI9_5_IRQn 0 */
	if(__HAL_GPIO_EXTI_GET_IT(INT1_Pin) != 0x00u){
		__HAL_GPIO_EXTI_CLEAR_IT(INT1_Pin);
		S1_READY = 1;
	}

	/* USER CODE BEGIN EXTI9_5_IRQn 1 */
	if(__HAL_GPIO_EXTI_GET_IT(INT2_Pin) != 0x00u){
		__HAL_GPIO_EXTI_CLEAR_IT(INT2_Pin);
		S2_READY = 1;
	}
}

We set up the I2C connections towards the sensors and the serial communication with Ambient Light Controller

In void MX_USART2_UART_Init(void) found in file usart.c we add the code to start the DMA mode and to disable the Half transfer interrupt, we only keep the Transfer Complete interrupt active, this way we know when we have received a full data packet form Ambient Light Controller.

	static uint8_t rxBuffer[buffSize];//ESP receive buffer
	volatile uint8_t newGain;
	.......................................................................
	/* USER CODE BEGIN USART2_Init 2 */
	//Start DMA RX and disable the half interrupt
	HAL_UART_Receive_DMA (&huart2, rxBuffer, buffSize);
	__HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);
	/* USER CODE END USART2_Init 2 */

To avoid any confusion, in usart.h file we need to add

#define buffSize	3 //1 byte gain and 2 markers
#define sMarker			60//<
#define eMarker			62//>
extern volatile uint8_t newGain;

where:

- buffSize is the size of the serial buffer

- s/eMarker are packet delimiters

- newGain is used to let the main app when we have new data packet from Ambient Light Controller

In the same file we must add the handler for usart DMA interrupt RX Transfer complete.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle){
	//Data from ESP Sensor
	if((rxBuffer[0] == sMarker) && (rxBuffer[2] == eMarker)){
		//Because accepted values are 1, 4, 16 and 60
		newGain = rxBuffer[1];
	}
  HAL_UART_Receive_DMA (&huart2, rxBuffer, buffSize);
  __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT);	
}

We set up the sensors before the main loop and then

- if we have new data packet coming from Ambient Light Controller we set the sensors gain and reset the newGain value

- If we get data from first sensor, we normalize the Red, Green and Blue values considering the Clear value directly in the send buffer, we reset the interrupt variable and we set the update variable

- We do the same thing for the second sensor

- When we have values from both sensors, we calculate the average and we fill the buffer to send

- we send the values using DMA and reset the update variables

		//When we get new value for gain from controller 
		if(newGain) {
			TCS3471_SetCurrent(0);
			TCS3471_setGain(newGain);
			TCS3471_SetCurrent(1);
			TCS3471_setGain(newGain);
			newGain = 0;
		}
		
		//We get the colors as 16bit integers and we need to scale them down to 8 bits
		//Top Sensor - near debug interface
		if(S1_READY) {
			S1_READY = 0;
			TCS3471_SetCurrent(0);
			get_CRGB(&c, &r, &g, &b);
			colorsToSend[0] = coeff*((double)r/(double)c);
			colorsToSend[1] = coeff*((double)g/(double)c);
			colorsToSend[2] = coeff*((double)b/(double)c);
			doUpdate1 = 1;
		}
		//Bottom Sensor
		if(S2_READY) {
			S2_READY = 0;
			TCS3471_SetCurrent(1);
			get_CRGB(&c, &r, &g, &b);
			colorsToSend[6] = coeff*((double)r/(double)c);
			colorsToSend[7] = coeff*((double)g/(double)c);
			colorsToSend[8] = coeff*((double)b/(double)c);
			doUpdate2 = 1;
		}

		// We need to average the values (Top sensor, (Top+Bottom/2),  Bottom sensor)
		if(doUpdate1 && doUpdate2){
			colorsToSend[3] = sqrt((colorsToSend[0]*colorsToSend[0] + colorsToSend[6]*colorsToSend[6])/2);
			colorsToSend[4] = sqrt((colorsToSend[1]*colorsToSend[1] + colorsToSend[7]*colorsToSend[7])/2);
			colorsToSend[5] = sqrt((colorsToSend[2]*colorsToSend[2] + colorsToSend[8]*colorsToSend[8])/2);
			HAL_UART_Transmit_DMA(&huart2, colorsToSend, ArrSize);
			doUpdate1 = doUpdate2 = 0;
		}

The whole software packet can be downloaded here.

Comments powered by CComment