I2C and Led Blinking

Hello,
This is my first time here so, sorry for any mistake I make…

I’m trying to do a school project and the ideia is to read from the gyroscope via I2C and blink one led (for debug pruposes)

However, I manage only to get the I2C printed in a display (everything is ok in this part) but the led isn’t blinking.

Need some help to understand why I the led isn’t working

Thank you,
Eddy



/* Standard includes. */
#include <string.h>
#include <stdio.h>
#include <stdint.h>

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "lcd.h"

/* Mutex include */
#include "semphr.h"

/* Queue include */
#include "queue.h"

/* I2C Task */
static void prvI2CTask(void *pvParameters);

/* Configure RCC clock at 72 MHz */
static void prvSetupRCC(void);

/* Configure GPIO. */
static void prvSetupGPIO(void);

/* Simple LED toggle task. */
static void prvFlashTask1(void *pvParameters);

/* Task that sends the task list to USART */
static void prvFlashTask6(void *pvParameters);

/********** Useful functions **********/
/* USART2 configuration. */
static void prvSetupUSART2(void);

/* USART2 send message. */
static void prvSendMessageUSART2(char *message);

/***************************************/

/* Task 1 handle variable. */
TaskHandle_t HandleTask1;
TaskHandle_t HandleTask5;
//TaskHandle_t HandleTask6;

#define mainI2C_DELAY			( ( TickType_t ) 1000 / portTock_PERIOD_MS )
void Config_GPIO_USART_I2C();
void Init_I2C();
static int8_t ReadFromAccel(uint8_t Adress, uint8_t Register);
void i2c_write(uint8_t address, uint8_t data, uint8_t Register);
void Config_GPIO_Sensor();

int main(void) {
	/*Setup the hardware, RCC, GPIO, etc...*/
	prvSetupRCC();
	prvSetupGPIO();
	prvSetupUSART2();

	/* Create the tasks */
	xTaskCreate(prvFlashTask1, "Flash1", configMINIMAL_STACK_SIZE, NULL, 1, &HandleTask1);
	xTaskCreate(prvI2CTask, "prvI2CTask", configMINIMAL_STACK_SIZE, NULL, 1, &HandleTask5);
	
	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the idle task. */
	return 0;
}
/*-----------------------------------------------------------*/

static void prvFlashTask1(void *pvParameters) {
	/* Declare the variable xLastExecutionTime */
	TickType_t xLastExecutionTime;

	/* Initialize xLastExecutionTime */
	xLastExecutionTime = xTaskGetTickCount();

	for (;;) {
		/* Block 1 second. */
		/* vTaskDelay((TickType_t )1000/portTICK_PERIOD_MS); comment this line */
		vTaskDelayUntil(&xLastExecutionTime, (TickType_t)1000/portTICK_PERIOD_MS);

		/* Toggle the LED */
		GPIO_WriteBit(GPIOB, GPIO_Pin_6, (1 - GPIO_ReadOutputDataBit( GPIOB, GPIO_Pin_6)));
		//		prvSendMessageUSART2("Mensagen enviada ao fim de 10 ms a partir de uma tarefa de baixa prioridade.\r\n");
	}
	//	for (i = 0; i < 65535; i++) {
	//	}
}
/*-----------------------------------------------------------*/

static void prvI2CTask(void *pvParameters) {
	lcd_init();

	char buffer_USART[100], data_buffer[10], buffer[20];
	uint8_t deviceID = ReadFromAccel(0xA6, 0x00);

	for (;;) {
		if (deviceID == 0b11100101) {
			sprintf(buffer_USART, "Device 0xE5 OK\n");
			prvSendMessageUSART2(buffer_USART);
			lcd_draw_string(5, 0, "Device 0xE5 OK", 0xFFFF, 1);
			display();
			i2c_write(0xA6, 0x00, 0x2D); // reset a todos os bits do Registo 0x2D - Power_CTL
			i2c_write(0xA6, 0x01, 0x31); // escala +- 4g
			i2c_write(0xA6, 0x08, 0x2D); // medição e "wake up" 8hz
			/*
			 * Os dados estão armazenados nos registos 0x32 a 0x37 na forma de DATAX0, DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1.
			 * Os registos são de 8 bits.
			 *
			 * Accel_X_RAW | Accel_Y_RAW | Accel_Z_RAW obtêm-se concatenando os dois registos, o que implica deslocar os 8 MSB bits para a esquerda
			 */

			data_buffer[0] = (ReadFromAccel(0xA6, 0x32));
			data_buffer[1] = ReadFromAccel(0xA6, 0x33);
			int Accel_X_RAW = (int16_t) (data_buffer[1] << 8 | data_buffer[0]);

			data_buffer[2] = ReadFromAccel(0xA6, 0x34);
			data_buffer[3] = ReadFromAccel(0xA6, 0x35);
			int Accel_Y_RAW = (int16_t) (data_buffer[3] << 8 | data_buffer[2]);

			data_buffer[4] = ReadFromAccel(0xA6, 0x36);
			data_buffer[5] = ReadFromAccel(0xA6, 0x37);
			int Accel_Z_RAW = (int16_t) (data_buffer[5] << 8 | data_buffer[4]);

			/* Uma vez que o formato float não está disponível, calcula-se o quociente e o resto da divisão
			 * para poder ser apresentada no display presente na placa de expansão
			 *
			 * Pela consulta do datasheet e pelas escala configurada - obtêm-se os valores lidos dos registos, dividindo por 128.205 LSB/mg
			 * ou multiplicando por 78mg/LSB
			 */

			int AxI = Accel_X_RAW / 128.205;
			int RestoAxI = Accel_X_RAW - (128.205 * AxI);
			RestoAxI = (RestoAxI / 128.205) * 100;

			/* Converter o cálculo do resto num número positivo */
			if (RestoAxI < 0) {
				RestoAxI = (-1) * RestoAxI;
			}

			/* Apresentação dos resultados na USART e display */

			if (Accel_X_RAW < 0) {
				sprintf(buffer, "x=-%d,%d", AxI, RestoAxI);
				lcd_draw_string(5, 25, (char*) buffer, 0x07F0, 1);
				display();
			} else {
				sprintf(buffer, "x=%d,%d", AxI, RestoAxI);
				lcd_draw_string(5, 25, (char*) buffer, 0x07F0, 1);
				display();
			}

			int AyI = Accel_Y_RAW / 128.205;
			int RestoAyI = Accel_Y_RAW - (128.205 * AyI);
			RestoAyI = (RestoAyI / 128.205) * 100;

			if (RestoAyI < 0) {
				RestoAyI = (-1) * RestoAyI;
			}

			if (Accel_Y_RAW < 0) {
				sprintf(buffer, "y=-%d,%d", AyI, RestoAyI);
				lcd_draw_string(5, 35, (char*) buffer, 0x07F0, 1);
				display();
			} else {
				sprintf(buffer, "y=%d,%d", AyI, RestoAyI);
				lcd_draw_string(5, 35, (char*) buffer, 0x07F0, 1);
				display();
			}

			int AzI = Accel_Z_RAW / 128.205;
			int RestoAzI = Accel_Z_RAW - (128.205 * AzI);
			RestoAzI = (RestoAzI / 128.205) * 100;

			if (RestoAzI < 0) {
				RestoAzI = (-1) * RestoAzI;
			}

			if (Accel_Z_RAW < 0) {
				sprintf(buffer, "z=-%d,%d", AzI, RestoAzI);
				lcd_draw_string(5, 45, (char*) buffer, 0x07F0, 1);
				display();
			} else {
				sprintf(buffer, "z=%d,%d", AzI, RestoAzI);
				lcd_draw_string(5, 45, (char*) buffer, 0x07F0, 1);
				display();
			}
			sprintf(buffer_USART, "(x,y,z)=(%d.%d, %d.%d, %d.%d)\n", AxI, RestoAxI, AyI, RestoAyI, AzI, RestoAzI);
			prvSendMessageUSART2(buffer_USART);
		} else {
			sprintf(buffer_USART, "DeviceID not found\n");
			prvSendMessageUSART2(buffer_USART);
			lcd_draw_string(0, 0, "DeviceID not found", 0xFFFF, 1);
			display();
		}
	}
}
/*-----------------------------------------------------------*/

//static void prvFlashTask6(void *pvParameters) {
//	char info[256];
//	TickType_t xLastExecutionTime;
//
//	xLastExecutionTime = xTaskGetTickCount();
//	for (;;) {
//		vTaskDelayUntil(&xLastExecutionTime,(TickType_t)1000/portTICK_PERIOD_MS);
//		prvSendMessageUSART2("----------------------------------------------------------------------------------------\n");
//		vTaskList(info);
//		prvSendMessageUSART2(info);
//	}
//}
/*-----------------------------------------------------------*/

static void prvSetupRCC(void) {
	/* RCC configuration - 72 MHz */
	ErrorStatus HSEStartUpStatus;

	RCC_DeInit();
	/*Enable the HSE*/
	RCC_HSEConfig(RCC_HSE_ON);
	/* Wait untill HSE is ready or time out */
	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	if (HSEStartUpStatus == SUCCESS) {
		/* Enable The Prefetch Buffer */
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
		/* 72 MHZ - 2 wait states */
		FLASH_SetLatency(FLASH_Latency_2);

		/* No division HCLK = SYSCLK = 72 MHz*/
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
		/* PCLK1 = HCLK/2 (36MHz) */
		RCC_PCLK1Config(RCC_HCLK_Div2);
		/* PCLK2 = HCLK (72MHz)*/
		RCC_PCLK2Config(RCC_HCLK_Div1);

		/* Use PLL with HSE = 12 MHz (12 MHz * 6 = 72 MHz) */
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6);
		/* Enable the PLL */
		RCC_PLLCmd(ENABLE);
		/* Wait for PLL ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
			;

		/* Select the PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		/* Wait until PLL is used as system clock */
		while (RCC_GetSYSCLKSource() != 0x08)
			;
	} else {
		/* HSE error? No further action */
		while (1)
			;
	}
}
/*-----------------------------------------------------------*/

static void prvSetupGPIO(void) {
	/* GPIO configuration */
	GPIO_InitTypeDef GPIO_InitStructure;

	/* Enable GPIOB clock */
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA,
			ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(GPIOA, &GPIO_InitStructure);

}
/*-----------------------------------------------------------*/

void prvSetupUSART2(void) {
	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	/* USART2 is configured as follow:
	 - BaudRate = 115200 baud
	 - Word Length = 8 Bits
	 - 1 Stop Bit
	 - No parity
	 - Hardware flow control disabled (RTS and CTS signals)
	 - Receive and transmit enabled */

	/* Enable GPIOA clock */
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
	/* USART Periph clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	/* Tx an AF */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/* RX as In Floating*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	/* 115200 8N1*/
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl =
			USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

	/* Configure the USART2 */
	USART_Init(USART2, &USART_InitStructure);
	/* Enable the USART2 */
	USART_Cmd(USART2, ENABLE);
}

/*-----------------------------------------------------------*/

/* This is a !blocking! send USART function */
static void prvSendMessageUSART2(char *message) {
	uint16_t cont_aux = 0;
	uint16_t nbytes = 0;

	nbytes = strlen(message);
	while (cont_aux != nbytes) {
		USART_SendData(USART2, (uint8_t) message[cont_aux]);
		while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET) {
		}
		cont_aux++;
	}
}
/*-----------------------------------------------------------*/

/* Inicializa o I2C */
void Init_I2C() {
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	I2C_InitTypeDef I2C_InitStructure;

	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 400000;
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_Cmd(I2C1, ENABLE);
}

static int8_t ReadFromAccel(uint8_t Adress, uint8_t Register) {
	int8_t value;

	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
		;

	I2C_GenerateSTART(I2C1, ENABLE); //Start
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
		;

	I2C_Send7bitAddress(I2C1, Adress, I2C_Direction_Transmitter); //Slave Address + Write
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
		; //Acknowledge acknowledge

	I2C_SendData(I2C1, Register);
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
		;

	I2C_GenerateSTART(I2C1, ENABLE);
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
		;

	I2C_Send7bitAddress(I2C1, Adress, I2C_Direction_Receiver);
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
		;
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
		;

	value = I2C_ReceiveData(I2C1);
	I2C_AcknowledgeConfig(I2C1, DISABLE); // NACK
	I2C_GenerateSTOP(I2C1, ENABLE);

	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
		;

	return value;
}

/* Escreve no "Slave" - Sensor */
void i2c_write(uint8_t address, uint8_t data, uint8_t Register) {

	/* enviar comando */
	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
		;

	I2C_GenerateSTART(I2C1, ENABLE);
	while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS)
		;

	I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter);
	while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)
			!= SUCCESS)
		;

	I2C_SendData(I2C1, Register);
	while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
		;

	I2C_SendData(I2C1, data);
	while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
		;

	I2C_GenerateSTOP(I2C1, ENABLE);
}

I think the stack size is way too small at least for the I2C task using (stack hungry) sprintf etc. I wonder why often in problem reports people use the bare minimum stack size FreeRTOS requires for their application tasks :thinking:
Did you define configASSERT , enabled stack overflow checking for development/debugging ? That’s important and very helpful.
Also once both tasks are running you might encounter unstable blinking experience because the I2C task is basically a busy loop since there is no blocking call nor a delay giving up the CPU to the other task and both tasks have the same priority.
Given you configured FreeRTOS using preemptive scheduling (default) and the SysTick resp. FreeRTOS tick works properly, you could give the blinking task a higher prio for best blinking experience :slight_smile:

1 Like

Hello,
Thank you for your reply…

I did that - give the led high priority… nothing, still not blinking

EDIT: I changed the stacksize from 128 to 256 and… now everything works fine.

NEXT STEP: Send the data to USART with queues messages

Personally, I’d give a bit more of a stack for the I2C comms task.

I think probably because generally the person has not used the task API before, and probably experience is also lacking in data structures, memory allocation and manipulation, etc.

saying for a friend obviously :wink:

1 Like