====== Lab08 - LCD display and HAL libraries ====== The previous examples used StdPeriph (standard peripheral) libraries to control the basic functionality of the Nucleo board. All the future projects will use HAL (hardware abstraction layer) and BSP (board support package) libraries. The project is available as {{courses:be5b99cpl:labs:prjcpl_lcd.tar.gz|}}. The sample project provides the basic functionality demonstration over: * Serial line (ST Link) * Joystick (Adafruit) * LCD and drawing (Adafruit) * Timers (HAL) * String manipulation (C lib) The resulting application works such as: * Joystick press - clears the display and sends data over serial line. * Joystick movements - displays pictorgams in dispaly corners. * Reception of character '0' draws a circle in the middle of the display while the parameters are scanned from a sample string. * Every second elapsed time is drawn on the display. ===== How to use the template project ===== The template project is available as {{courses:be5b99cpl:labs:prjcpl_lcd.tar.gz|}}. The recomended solution to make it work is as follows: * Create a new workspace in Eclipse (System Workbench) - select File > Switch workspace > other and create a new one. * Download the project and copy the prjCPL_LCD folder into the workspace folder. * Import the project into the workspace through: File > Import, select General > Existing Projects into Workspace. Then select the project root directory (locate the prjCPL_LCD folder on your filesystem) and press Finish button. * Build the project through: Project > Build All. * And upload the project into the board with Run > Debug as > Ac6 C/Cpp Application. ===== The exercise objective ===== * Make the template project working with your board. * Start writing the code to receive data from serial line into a buffer to be able to parse commands from PC ===== The code ===== This is the content of the main.c file for above mentioned functionality. This code will work only with HAL libraries. How to import the project into the workspace is described above. // // ****************************************************************************** // @file main.c // @author CPL (Pavel Paces, based on STM examples and HAL library) // @version V0.0 // @date 02-November-2016 // @brief Adafruit 802 display shield and serial line over ST-Link example // Nucleo STM32F401RE USART2 (Tx PA.2, Rx PA.3) // // ****************************************************************************** // // // Basic framework #include "stm32f4xx.h" #include "stm32f4xx_nucleo.h" #include "stm32_adafruit_lcd.h" #include UART_HandleTypeDef hUART2; /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ static void Error_Handler(void) { /* User may add here some code to deal with this error */ while(1) { } } /** * @brief System Clock Configuration * The system Clock is configured as follow : * System Clock source = PLL (HSI) * SYSCLK(Hz) = 84000000 * HCLK(Hz) = 84000000 * AHB Prescaler = 1 * APB1 Prescaler = 2 * APB2 Prescaler = 1 * HSI Frequency(Hz) = 16000000 * PLL_M = 16 * PLL_N = 336 * PLL_P = 4 * PLL_Q = 7 * VDD(V) = 3.3 * Main regulator output voltage = Scale2 mode * Flash Latency(WS) = 2 * @param None * @retval None */ static void SystemClock_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; /* Enable Power Control clock */ __HAL_RCC_PWR_CLK_ENABLE(); /* The voltage scaling allows optimizing the power consumption when the device is clocked below the maximum system frequency, to update the voltage scaling value regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); /* Enable HSI Oscillator and activate PLL with HSI as source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 6; //0x10; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 16; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; RCC_OscInitStruct.PLL.PLLQ = 7; if( HAL_RCC_OscConfig( &RCC_OscInitStruct ) != HAL_OK ) { Error_Handler(); } /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } /* __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); */ } /** * @brief Serial port settings * @param None * @retval None */ static void initUSART( void ) { GPIO_InitTypeDef GPIO_InitStruct; __GPIOA_CLK_ENABLE(); __USART2_CLK_ENABLE(); // **USART2 GPIO Configuration // PA2 ------> USART2_TX // PA3 ------> USART2_RX GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init( GPIOA, &GPIO_InitStruct ); hUART2.Instance = USART2; hUART2.Init.BaudRate = 9600;//115200; hUART2.Init.WordLength = UART_WORDLENGTH_8B; hUART2.Init.StopBits = UART_STOPBITS_1; hUART2.Init.Parity = UART_PARITY_NONE; hUART2.Init.Mode = UART_MODE_TX_RX; hUART2.Init.HwFlowCtl = UART_HWCONTROL_NONE; hUART2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init( &hUART2 ) != HAL_OK) { Error_Handler(); } } // END void initUSART( void ) #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 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) */ /* Infinite loop */ while (1) { } } #endif /** * @brief main function * @param None * @retval None */ void main(void) { // timer settings uint32_t uiTicks, uiSec; // display tmp variables uint32_t uiDispCentX, uiDispCentY; // joystick operation JOYState_TypeDef oJoyState; // serial port i/o and status #define cREVC_MAX 8 uint8_t chArr[cREVC_MAX]; HAL_StatusTypeDef oRecvStatus; // data reception uint32_t uiSerRecv; // // initialization of variables uiSec = 0; uiSerRecv = 0; // // System init HAL_Init(); // Configure the System clock to 84 MHz SystemClock_Config(); // serial port initUSART(); // Nucleo User LED init BSP_LED_Init( LED2 ); // and usage BSP_LED_Off( LED2 ); HAL_Delay( 1000 ); BSP_LED_On( LED2 ); HAL_Delay( 1000 ); BSP_LED_Toggle( LED2 ); // Nucleo user button init BSP_PB_Init( BUTTON_USER, BUTTON_MODE_GPIO ); // Adafruit joystick init (void)BSP_JOY_Init(); // // Adafruit LCD init BSP_LCD_Init(); uiDispCentX = BSP_LCD_GetXSize()/2; uiDispCentY = BSP_LCD_GetYSize()/2; // // some drawings BSP_LCD_Clear( LCD_COLOR_GREEN ); BSP_LCD_DrawLine( 10, 10, 128-10, 10 ); BSP_LCD_SetFont( &Font24 ); BSP_LCD_SetTextColor( LCD_COLOR_RED ); BSP_LCD_DisplayStringAtLine( 1, (uint8_t *)" Welcome to Nucleo! " ); while(1) // main loop { // // Receive serial data example oRecvStatus = HAL_UART_Receive( &hUART2, chArr, 1, 100 ); if( oRecvStatus == HAL_OK ) { uiSerRecv = chArr[0]; } // END if( oRecvStatus == HAL_OK ) // // Joystick reading example oJoyState = BSP_JOY_GetState(); switch( oJoyState ) { default: case JOY_NONE: break; case JOY_SEL: BSP_LCD_Clear( ); { char *msg = "Welcome to Nucleo!\n\r"; HAL_UART_Transmit( &hUART2, (uint8_t*)msg, strlen(msg), 0xFFFF); } BSP_LED_Toggle( LED2 );LCD_COLOR_WHITE break; case JOY_DOWN: BSP_LCD_SetTextColor( LCD_COLOR_GREEN ); BSP_LCD_DrawLine( uiDispCentX, uiDispCentY, uiDispCentX, uiDispCentY + 40 ); BSP_LCD_DrawCircle(BSP_LCD_GetXSize() - 15, BSP_LCD_GetYSize() - 15, 10); break; case JOY_LEFT: BSP_LCD_SetTextColor( LCD_COLOR_GREEN ); BSP_LCD_DrawLine( uiDispCentX - 40, uiDispCentY, uiDispCentX, uiDispCentY ); BSP_LCD_DrawCircle(15, BSP_LCD_GetYSize() - 15, 10); break; case JOY_RIGHT: BSP_LCD_SetTextColor( LCD_COLOR_GREEN ); BSP_LCD_DrawLine( uiDispCentX, uiDispCentY, uiDispCentX + 40, uiDispCentY); BSP_LCD_DrawCircle( BSP_LCD_GetXSize() - 15, 15, 10); break; case JOY_UP: BSP_LCD_SetTextColor( LCD_COLOR_GREEN ); BSP_LCD_DrawLine( uiDispCentX, uiDispCentY, uiDispCentX, uiDispCentY - 40 ); BSP_LCD_DrawCircle(15, 15, 10); break; } // end switch( oJoyState ) // // Button reading - the button is hidden under the display // uiButtState = BSP_PB_GetState( BUTTON_USER ); // // Timming - second counter if( (HAL_GetTick() - uiTicks) > 1000) { uint8_t chArr[40]; uiTicks = HAL_GetTick(); uiSec++; BSP_LCD_SetFont( &Font8 ); BSP_LCD_SetTextColor( LCD_COLOR_RED ); sprintf( (char *)chArr, (char *)" %d ", (int)uiSec ); BSP_LCD_DisplayStringAtLine( 14, chArr); } // END if( (HAL_GetTick() - uiTicks) > 1000) // // string manipulation example if( uiSerRecv == 0x30 ) { int iResult; char chArrTmpData[] = "DRAW:CIRCLE 64,80,30"; // !! has to be here uiSerRecv = 0; iResult = strstr(chArrTmpData, "DRAW"); if( iResult ) { int iXs, iYs, iRad; int iResult; iResult = sscanf( chArrTmpData, "DRAW:CIRCLE %d,%d,%d", &iXs, &iYs, &iRad ); if( iResult > 2 ) { BSP_LCD_DrawCircle( iXs, iYs, iRad ); } } } // END string manipulation example } // END while(1) } // END main