Posted on Leave a comment

Merge Sort is bad for Embedded System

Merge sort is good if your system has plenty of memory to accommodate the temporary array.

Embedded systems have very limited memory and it is often fixed.

If the system has some other function that also runs concurrently. Then that memory also gets shortened.

Merge sort is good for a bigger system like the personal computer and business computer which have the bigger memory in which all the temporary array can reside.

The advantage of merge sort is that it is stable.

Since it takes a lot of space it is not useful for an embedded system, as they have a very small memory sometimes it is just KilloByte.
example:
ATmega328p = 2KB SRAM
ATtiny85 = 512B SRAM

Code for STM32F429ZIT6

This code redirects the printf statements towards the asynchronous UART.
As the size of input array for merge sort increases the space required to store temporary element increases, which eventually leads to stalling of the program.
/* 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 */
#include "stdio.h"
#include "stdlib.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
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_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/*
* Function Name: _write
* Function Description: Redirect the printf() statement towards the UART using the HAL_UART_Transmit
Author: Abhay

*/
int _write(int fd, char* ptr, int len) {
    HAL_UART_Transmit(&huart1, (uint8_t *) ptr, len, HAL_MAX_DELAY);
 //   HAL_UART_Transmit(&huart1, ptr, len, Timeout)
    return len;
}

// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
	int i, j, k;
	int n1 = m - l + 1;
	int n2 = r - m;

	/* create temp arrays */
	int L[n1], R[n2];

	/* Copy data to temp arrays L[] and R[] */
	for (i = 0; i < n1; i++)
		L[i] = arr[l + i];
	for (j = 0; j < n2; j++)
		R[j] = arr[m + 1 + j];

	/* Merge the temp arrays back into arr[l..r]*/
	i = 0; // Initial index of first subarray
	j = 0; // Initial index of second subarray
	k = l; // Initial index of merged subarray
	while (i < n1 && j < n2) {
		if (L[i] <= R[j]) {
			arr[k] = L[i];
			i++;
		}
		else {
			arr[k] = R[j];
			j++;
		}
		k++;
	}

	/* Copy the remaining elements of L[], if there
	are any */
	while (i < n1) {
		arr[k] = L[i];
		i++;
		k++;
	}

	/* Copy the remaining elements of R[], if there
	are any */
	while (j < n2) {
		arr[k] = R[j];
		j++;
		k++;
	}
}

/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
	if (l < r) {
		// Same as (l+r)/2, but avoids overflow for
		// large l and h
		int m = l + (r - l) / 2;

		// Sort first and second halves
		mergeSort(arr, l, m);
		mergeSort(arr, m + 1, r);

		merge(arr, l, m, r);
	}
}

/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
	int i;
	for (i = 0; i < size; i++)
		printf("%d ", A[i]);
	printf("\n");
}

/* 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_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  int arr[] = { 12, 11, 13, 5, 6, 7,12};
        int arr_size = sizeof(arr) / sizeof(arr[0]);

//        for( int temp=0; temp<1023;temp++){
//  	arr[temp] = rand()*1000;
//  }
        printf("Given array is \n");
        printArray(arr, arr_size);

        mergeSort(arr, 0, arr_size - 1);

        printf("\nSorted array is \n");
        printArray(arr, arr_size);
     //   return 0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* 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_SCALE3);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @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};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOG, ledg_Pin|ledr_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : ledg_Pin ledr_Pin */
  GPIO_InitStruct.Pin = ledg_Pin|ledr_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* 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 */
Posted on Leave a comment

How to connect STM32F429I-DISC1 board to DS1307 using I2C

On the STM32F429 board, there is one I2c extension connector. This connector has eight pins. Which is used to connect to other I2C peripherals such as RTC, EEPROM and other microcontrollers etc.

DS1307 connected to I2C

In the hardware schematics, it is labelled as ACP/RF E2P connector.

The I2C3 SDA and SCL lines are pulled up via a 4.7 k ohm resistor to VCC 3.3V.

This is the basic code that I used to set/get the data in/from the DS1307 via I2c.

/* USER CODE BEGIN 4 */
struct Time{
	  uint8_t sec;
	  uint8_t min;
	  uint8_t hour;
	  uint8_t weekday;
	  uint8_t day;
	  uint8_t month;
	  uint8_t year;
	  };

/* USER CODE END 4 */

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
  /* init code for USB_HOST */
  MX_USB_HOST_Init();
  /* USER CODE BEGIN 5 */
 char buff[30];
  uint8_t *ptr1;
  uint8_t *ptr2;
  ptr2 = (uint8_t *)buff;

  struct Time Set_time,Get_Time;

  Set_time.sec = 0;
  Set_time.min = 0;
  Set_time.hour = 0;
  Set_time.day = 0;
  Set_time.month = 04;
  Set_time.year = 0;
  Set_time.weekday = 0;

  HAL_I2C_Mem_Write(&hi2c3, 0xd0, 0, 1,&Set_time.sec, 7, 1000);



  /* Infinite loop */
  for(;;)
  {
	 
	  HAL_I2C_Mem_Read(&hi2c3, 0xD1, 0, 1, &Get_Time.sec, 7, 1000);
    osDelay(1000);
    ptr1 = (uint8_t *)"Hello\n";
    HAL_UART_Transmit(&huart1, ptr1, 6, 1000);
    sprintf(buff,"%02x:%02x:%02x - %02x - %02x/%02x/%02x \n",
    		Get_Time.hour,
			Get_Time.min,
			Get_Time.sec,
			Get_Time.weekday,
			Get_Time.day,
			Get_Time.month,
			Get_Time.year);
    HAL_UART_Transmit(&huart1, ptr2,26, 1000);
  }
  /* USER CODE END 5 */
}

In this code, I created a structure for the time, weekday and date. Which is similar to the internal registers of DS1307.

The Structure then creates two instances called set_time and Get_time. The Set_time object is filled with the values and then its location is transfered to the HAL_I2C_Mem_Write function. Which sends this data through polling to the DS1307.

Similarly the Get_time structure is used to retrieve the data from the DS1307 using the HAL_I2C_Mem_Read function. Which reads 7 bytes from the DS1307.

The retrieved time and date are then sent via the UART to display on a terminal.

Posted on Leave a comment

STM32F429I-DISC1

Datasheet for stm32F429ZI https://www.st.com/en/microcontrollers-microprocessors/stm32f429zi.html

This board have a 2.4 Resistive touch TFT LCD. which uses the ILI9341  controller.

The touch screen which I got with this display is very bad. you have to press down on the screen before you power ON the device.

The microcontroller is based on the ARM CORTEX M4F which can be clocked up to 180MHz. This particular board has an 8Mbyte of SDRAM included which is basically useless with this screen. If you want to see the full potential you have to use the LTDC peripheral which when configured with DMA2D gives you a very powerful development board with multimedia capabilites.