├── ECUAL ├── BUTTONS │ ├── BUTTONS.c │ ├── BUTTONS.h │ ├── BUTTONS_cfg.c │ └── BUTTONS_cfg.h ├── DC_MOTOR │ ├── DC_MOTOR.c │ ├── DC_MOTOR.h │ ├── DC_MOTOR_cfg.c │ └── DC_MOTOR_cfg.h ├── DOT_MATRIX │ ├── DOT_MATRIX.c │ ├── DOT_MATRIX.h │ ├── DOT_MATRIX_cfg.c │ └── DOT_MATRIX_cfg.h ├── HCSR04 │ ├── HCSR04.c │ ├── HCSR04.h │ ├── HCSR04_cfg.c │ └── HCSR04_cfg.h ├── I2C_LCD │ ├── I2C_LCD.c │ ├── I2C_LCD.h │ ├── I2C_LCD_cfg.c │ └── I2C_LCD_cfg.h ├── JOYSTICK │ ├── JOYSTICK.c │ ├── JOYSTICK.h │ ├── JOYSTICK_cfg.c │ └── JOYSTICK_cfg.h ├── KEYPAD │ ├── KEYPAD.c │ ├── KEYPAD.h │ ├── KEYPAD_cfg.c │ └── KEYPAD_cfg.h ├── LCD16X2 │ ├── LCD16X2.c │ ├── LCD16X2.h │ ├── LCD16X2_cfg.c │ └── LCD16X2_cfg.h ├── LEDS │ ├── LEDS.c │ ├── LEDS.h │ ├── LEDS_cfg.c │ └── LEDS_cfg.h ├── LM35 │ ├── LM35.c │ ├── LM35.h │ ├── LM35_cfg.c │ └── LM35_cfg.h ├── SERVO │ ├── SERVO.c │ ├── SERVO.h │ ├── SERVO_cfg.c │ └── SERVO_cfg.h ├── SEVEN_SEGMENTS │ ├── SEVEN_SEGMENTS.c │ ├── SEVEN_SEGMENTS.h │ ├── SEVEN_SEGMENTS_cfg.c │ └── SEVEN_SEGMENTS_cfg.h └── STEPPER │ ├── STEPPER.c │ ├── STEPPER.h │ ├── STEPPER_cfg.c │ └── STEPPER_cfg.h ├── MATH ├── FIR │ ├── FIR.c │ └── FIR.h ├── MATH.c └── MATH.h ├── MIDWARE ├── FATFS_SD │ ├── FATFS_SD.c │ └── FATFS_SD.h └── FEE │ ├── FEE.c │ └── FEE.h ├── README.md └── util ├── Util.c └── Util.h /ECUAL/BUTTONS/BUTTONS.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: BUTTONS.c 3 | * Driver Name: [[ BUTTONS Driver ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | 14 | #include "BUTTONS.h" 15 | #include "BUTTONS_cfg.h" 16 | #include "../../MATH/FIR/FIR.h" 17 | 18 | FIR_Filter_cfg BTNS_Filters[BTN_UNITS] = {0}; 19 | uint8_t* gu8_BTN_States; 20 | 21 | 22 | void BTNs_Init(uint8_t* BTN_States) 23 | { 24 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 25 | uint8_t i = 0; 26 | 27 | for(i=0; iCCR1 = au16_SPEED; 118 | } 119 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_2) 120 | { 121 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR2 = au16_SPEED; 122 | } 123 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_3) 124 | { 125 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR3 = au16_SPEED; 126 | } 127 | else 128 | { 129 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR4 = au16_SPEED; 130 | } 131 | } 132 | 133 | void DC_MOTOR_Set_Speed(uint8_t au8_MOTOR_Instance, uint16_t au16_SPEED) 134 | { 135 | /* Write The Speed Value To The PWM CH DutyCycle Register */ 136 | if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_1) 137 | { 138 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR1 = au16_SPEED; 139 | } 140 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_2) 141 | { 142 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR2 = au16_SPEED; 143 | } 144 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_3) 145 | { 146 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR3 = au16_SPEED; 147 | } 148 | else 149 | { 150 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR4 = au16_SPEED; 151 | } 152 | } 153 | 154 | void DC_MOTOR_Set_Dir(uint8_t au8_MOTOR_Instance, uint8_t au8_DIR) 155 | { 156 | /* Write To The 2 Direction Control Pins */ 157 | if(au8_DIR == DIR_CW) 158 | { 159 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_PIN, 1); 160 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_PIN, 0); 161 | } 162 | else if(au8_DIR == DIR_CCW) 163 | { 164 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_PIN, 0); 165 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_PIN, 1); 166 | } 167 | } 168 | 169 | void DC_MOTOR_Stop(uint8_t au8_MOTOR_Instance) 170 | { 171 | /* Write To The 2 Direction Control Pins */ 172 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR1_PIN, 0); 173 | HAL_GPIO_WritePin(DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_GPIO, DC_MOTOR_CfgParam[au8_MOTOR_Instance].DIR2_PIN, 0); 174 | 175 | /* Write ZERO To The PWM Ch DutyCycle Register */ 176 | if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_1) 177 | { 178 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR1 = 0; 179 | } 180 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_2) 181 | { 182 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR2 = 0; 183 | } 184 | else if(DC_MOTOR_CfgParam[au8_MOTOR_Instance].PWM_TIM_CH == TIM_CHANNEL_3) 185 | { 186 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR3 = 0; 187 | } 188 | else 189 | { 190 | DC_MOTOR_CfgParam[au8_MOTOR_Instance].TIM_Instance->CCR4 = 0; 191 | } 192 | } 193 | 194 | uint32_t DC_MOTOR_Get_MaxFreq(uint8_t au8_MOTOR_Instance) 195 | { 196 | uint32_t ARR_Value = 1; 197 | uint8_t i = 0; 198 | 199 | for(i=0; i 67 | {0b00000010,0b00000001,0b01010001,0b00001001,0b00000110}, // ? 68 | {0b00110010,0b01001001,0b01111001,0b01000001,0b00111110}, // @ 69 | {0b01111110,0b00010001,0b00010001,0b00010001,0b01111110}, // A 70 | {0b01111111,0b01001001,0b01001001,0b01001001,0b00111110}, // B 71 | {0b00111110,0b01000001,0b01000001,0b01000001,0b00100010}, // C 72 | {0b01111111,0b01000001,0b01000001,0b01000001,0b00111110}, // D 73 | {0b01111111,0b01001001,0b01001001,0b01001001,0b01001001}, // E 74 | {0b01111111,0b00001001,0b00001001,0b00001001,0b00000001}, // F 75 | {0b00111110,0b01000001,0b01001001,0b01001001,0b00111010}, // G 76 | {0b01111111,0b00001000,0b00001000,0b00001000,0b01111111}, // H 77 | {0b01000001,0b01000001,0b01111111,0b01000001,0b01000001}, // I 78 | {0b00110000,0b01000001,0b01000001,0b00111111,0b00000001}, // J 79 | {0b01111111,0b00001000,0b00010100,0b00100010,0b01000001}, // K 80 | {0b01111111,0b01000000,0b01000000,0b01000000,0b01000000}, // L 81 | {0b01111111,0b00000010,0b00001100,0b00000010,0b01111111}, // M 82 | {0b01111111,0b00000100,0b00001000,0b00010000,0b01111111}, // N 83 | {0b00111110,0b01000001,0b01000001,0b01000001,0b00111110}, // O 84 | {0b01111111,0b00001001,0b00001001,0b00001001,0b00000110}, // P 85 | {0b00111110,0b01000001,0b01010001,0b00100001,0b01011110}, // Q 86 | {0b01111111,0b00001001,0b00001001,0b00011001,0b01100110}, // R 87 | {0b01000110,0b01001001,0b01001001,0b01001001,0b00110001}, // S 88 | {0b00000001,0b00000001,0b01111111,0b00000001,0b00000001}, // T 89 | {0b00111111,0b01000000,0b01000000,0b01000000,0b00111111}, // U 90 | {0b00001111,0b00110000,0b01000000,0b00110000,0b00001111}, // V 91 | {0b00111111,0b01000000,0b00111000,0b01000000,0b00111111}, // W 92 | {0b01100011,0b00010100,0b00001000,0b00010100,0b01100011}, // X 93 | {0b00000011,0b00000100,0b01111000,0b00000100,0b00000011}, // Y 94 | {0b01100001,0b01010001,0b01001001,0b01000101,0b01000011}, // Z 95 | {0b01111111,0b01000001,0b01000001,0b00000000,0b00000000}, // [ 96 | {0b00000010,0b00000100,0b00001000,0b00010000,0b00100000}, // '\' 97 | {0b00000000,0b00000000,0b01000001,0b01000001,0b01111111}, // ] 98 | {0b00000100,0b00000010,0b00000001,0b00000010,0b00000100}, // ^ 99 | {0b01000000,0b01000000,0b01000000,0b01000000,0b01000000}, // _ 100 | {0b00000000,0b00000001,0b00000010,0b00000100,0b00000000}, // ` 101 | {0b00100000,0b01010100,0b01010100,0b01010100,0b01111000}, // a 102 | {0b01111111,0b01001000,0b01000100,0b01000100,0b00111000}, // 0b 103 | {0b00111000,0b01000100,0b01000100,0b01000100,0b00100000}, // c 104 | {0b00111000,0b01000100,0b01000100,0b01001000,0b01111111}, // d 105 | {0b00111000,0b01010100,0b01010100,0b01010100,0b00011000}, // e 106 | {0b00001000,0b01111110,0b00001001,0b00000001,0b00000010}, // f 107 | {0b00001100,0b01010010,0b01010010,0b01010010,0b00111110}, // g 108 | {0b01111111,0b00001000,0b00000100,0b00000100,0b01111000}, // h 109 | {0b00000000,0b01000100,0b01111101,0b01000000,0b00000000}, // i 110 | {0b00100000,0b01000000,0b01000100,0b00111101,0b00000000}, // j 111 | {0b01111111,0b00010000,0b00101000,0b01000100,0b00000000}, // k 112 | {0b00000000,0b01000001,0b01111111,0b01000000,0b00000000}, // l 113 | {0b01111000,0b00000100,0b00001000,0b00000100,0b01111000}, // m 114 | {0b01111100,0b00001000,0b00000100,0b00000100,0b01111000}, // n 115 | {0b00111000,0b01000100,0b01000100,0b01000100,0b00111000}, // o 116 | {0b01111100,0b00010100,0b00010100,0b00010100,0b00001000}, // p 117 | {0b00001000,0b00010100,0b00010100,0b01111100,0b00000000}, // q 118 | {0b01111100,0b00001000,0b00000100,0b00000100,0b00001000}, // r 119 | {0b01001000,0b01010100,0b01010100,0b01010100,0b00100000}, // s 120 | {0b00000100,0b00111111,0b01000100,0b01000000,0b00100000}, // t 121 | {0b00111100,0b01000000,0b01000000,0b00100000,0b01111100}, // u 122 | {0b00011100,0b00100000,0b01000000,0b00100000,0b00011100}, // v 123 | {0b00111100,0b01000000,0b00110000,0b01000000,0b00111100}, // w 124 | {0b01000100,0b00101000,0b00010000,0b00101000,0b01000100}, // x 125 | {0b00001100,0b01010000,0b01010000,0b01010000,0b00111100}, // y 126 | {0b01000100,0b01100100,0b01010100,0b01001100,0b01000100}, // z 127 | {0b00000000,0b00001000,0b00110110,0b01000001,0b00000000}, // { 128 | {0b00000000,0b00000000,0b01111111,0b00000000,0b00000000}, // | 129 | {0b00000000,0b01000001,0b00110110,0b00001000,0b00000000}, // } 130 | {0b00001000,0b00000100,0b00000100,0b00001000,0b00000100} // ~ 131 | }; 132 | 133 | //-----------------------------[ Static Functions' Definitions ]---------------------------- 134 | 135 | // Static Functions Used By Library But Not Visible To User Who Include The Library (Driver) 136 | 137 | static void SPI_TX_Byte(uint8_t au8_DATA) 138 | { 139 | HAL_SPI_Transmit(g_hspi, &au8_DATA, 1, 10); 140 | } 141 | 142 | static void SS_ENABLE(uint8_t au8_MATRIX_Instance) 143 | { 144 | HAL_GPIO_WritePin(DOT_MATRIX_CfgParam[au8_MATRIX_Instance].SS_GPIO, DOT_MATRIX_CfgParam[au8_MATRIX_Instance].SS_PIN, 0); 145 | } 146 | 147 | static void SS_DISABLE(uint8_t au8_MATRIX_Instance) 148 | { 149 | HAL_GPIO_WritePin(DOT_MATRIX_CfgParam[au8_MATRIX_Instance].SS_GPIO, DOT_MATRIX_CfgParam[au8_MATRIX_Instance].SS_PIN, 1); 150 | } 151 | 152 | static void TxByte(uint8_t au8_MATRIX_Instance, uint8_t au8_Col, uint8_t au8_Val) 153 | { 154 | SS_ENABLE(au8_MATRIX_Instance); 155 | SPI_TX_Byte(au8_Col); 156 | SPI_TX_Byte(au8_Val); 157 | SS_DISABLE(au8_MATRIX_Instance); 158 | } 159 | 160 | static void DisplayBuffer(uint8_t au8_MATRIX_Instance) 161 | { 162 | uint8_t i = 0; 163 | 164 | for(i = 0; i i; k--) 177 | { 178 | SPI_TX_Byte(0x00); 179 | SPI_TX_Byte(0x00); 180 | } 181 | SS_DISABLE(au8_MATRIX_Instance); 182 | } 183 | } 184 | } 185 | 186 | static void PushToBuffer(uint8_t au8_MATRIX_Instance, uint8_t au8_NewByte) 187 | { 188 | uint8_t i = 0; 189 | 190 | for(i = 0; i < DOT_MATRIX_CfgParam[au8_MATRIX_Instance].CASCADED_DEVICES*8 - 1; i++) 191 | { 192 | gs_MATRIX_info[au8_MATRIX_Instance].Buffer[i] = gs_MATRIX_info[au8_MATRIX_Instance].Buffer[i+1]; 193 | } 194 | gs_MATRIX_info[au8_MATRIX_Instance].Buffer[DOT_MATRIX_CfgParam[au8_MATRIX_Instance].CASCADED_DEVICES*8 - 1] = au8_NewByte; 195 | } 196 | 197 | //----------------------------[ Library Functions' Definitions ]--------------------------- 198 | 199 | // Functions To Be Used By The User Who Include The Library (Driver) 200 | 201 | void DOT_MATRIX_Init(SPI_HandleTypeDef * hspi) 202 | { 203 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 204 | uint8_t i = 0, j = 0; 205 | 206 | g_hspi = hspi; 207 | 208 | /*--------[ Configure The SS GPIO Pins ]-------*/ 209 | for(i = 0; iInstance = DOT_MATRIX_SPI; 239 | g_hspi->Init.Mode = SPI_MODE_MASTER; 240 | g_hspi->Init.Direction = SPI_DIRECTION_2LINES; 241 | g_hspi->Init.DataSize = SPI_DATASIZE_8BIT; 242 | g_hspi->Init.CLKPolarity = SPI_POLARITY_LOW; 243 | g_hspi->Init.CLKPhase = SPI_PHASE_1EDGE; 244 | g_hspi->Init.NSS = SPI_NSS_SOFT; 245 | g_hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; 246 | g_hspi->Init.FirstBit = SPI_FIRSTBIT_MSB; 247 | g_hspi->Init.TIMode = SPI_TIMODE_DISABLE; 248 | g_hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; 249 | g_hspi->Init.CRCPolynomial = 10; 250 | HAL_SPI_Init(g_hspi); 251 | 252 | /*--------[ Initialize & Configure The MAX7219 Devices ]-------*/ 253 | for(i = 0; iInstance = MATRIX_TIMER; 322 | TMR_Handle->Init.Prescaler = 99; 323 | TMR_Handle->Init.CounterMode = TIM_COUNTERMODE_UP; 324 | TMR_Handle->Init.Period = ARR_Value-1; 325 | TMR_Handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 326 | TMR_Handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; 327 | HAL_TIM_Base_Init(TMR_Handle); 328 | sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 329 | HAL_TIM_ConfigClockSource(TMR_Handle, &sClockSourceConfig); 330 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 331 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 332 | HAL_TIMEx_MasterConfigSynchronization(TMR_Handle, &sMasterConfig); 333 | HAL_TIM_Base_Start_IT(TMR_Handle); 334 | } 335 | } 336 | 337 | void MATRIX_SCROLL_SetSpeed(uint8_t au8_MATRIX_Instance, uint16_t au16_SPEED) 338 | { 339 | gs_MATRIX_info[au8_MATRIX_Instance].Max_Ticks = au16_SPEED; 340 | } 341 | 342 | void MATRIX_CLEAR(uint8_t au8_MATRIX_Instance) 343 | { 344 | uint8_t i = 0, col = 1; 345 | 346 | for(i = 0; i= gs_MATRIX_info[i].Max_Ticks) 382 | { 383 | if(gs_MATRIX_info[i].BufferInit == 1 && DOT_MATRIX_CfgParam[i].SCROLL_Mode == SCROLL_MODE) 384 | { 385 | if(gs_MATRIX_info[i].Col_Index == 5) 386 | { 387 | gs_MATRIX_info[i].Arr_Index++; 388 | gs_MATRIX_info[i].Col_Index = 0; 389 | space = 1; 390 | } 391 | if(gs_MATRIX_info[i].Arr_Index == gs_MATRIX_info[i].ArrSize) 392 | { 393 | gs_MATRIX_info[i].Arr_Index = 0; 394 | } 395 | if(space) 396 | { 397 | PushToBuffer(i, 0x00); // Add White Space To Separate Characters 398 | } 399 | else 400 | { 401 | ch = (*(gs_MATRIX_info[i].ArrPtr + gs_MATRIX_info[i].Arr_Index)-32); 402 | PushToBuffer(i, FONT_7x5[ch][gs_MATRIX_info[i].Col_Index++]); 403 | } 404 | DisplayBuffer(i); 405 | } 406 | gs_MATRIX_info[i].Ticks = 0; 407 | } 408 | else 409 | { 410 | gs_MATRIX_info[i].Ticks++; 411 | } 412 | } 413 | } 414 | 415 | void MATRIX_TMR_OVF_ISR(TIM_HandleTypeDef* htim) 416 | { 417 | uint8_t i = 0, ch, space = 0; 418 | 419 | if(htim->Instance == MATRIX_TIMER) 420 | { 421 | for(i=0; i= gs_MATRIX_info[i].Max_Ticks) 424 | { 425 | if(gs_MATRIX_info[i].BufferInit == 1 && DOT_MATRIX_CfgParam[i].SCROLL_Mode == SCROLL_MODE) 426 | { 427 | if(gs_MATRIX_info[i].Col_Index == 5) 428 | { 429 | gs_MATRIX_info[i].Arr_Index++; 430 | gs_MATRIX_info[i].Col_Index = 0; 431 | space = 1; 432 | } 433 | if(gs_MATRIX_info[i].Arr_Index == gs_MATRIX_info[i].ArrSize) 434 | { 435 | gs_MATRIX_info[i].Arr_Index = 0; 436 | } 437 | if(space) 438 | { 439 | PushToBuffer(i, 0x00); // Add White Space To Separate Characters 440 | } 441 | else 442 | { 443 | ch = (*(gs_MATRIX_info[i].ArrPtr + gs_MATRIX_info[i].Arr_Index)-32); 444 | PushToBuffer(i, FONT_7x5[ch][gs_MATRIX_info[i].Col_Index++]); 445 | } 446 | DisplayBuffer(i); 447 | } 448 | gs_MATRIX_info[i].Ticks = 0; 449 | } 450 | else 451 | { 452 | gs_MATRIX_info[i].Ticks++; 453 | } 454 | } 455 | } 456 | } 457 | 458 | 459 | 460 | -------------------------------------------------------------------------------- /ECUAL/DOT_MATRIX/DOT_MATRIX.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DOT_MATRIX.h 3 | * Driver Name: [[ DOT MATRIX MAX7219 ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.0 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef DOT_MATRIX_H_ 15 | #define DOT_MATRIX_H_ 16 | 17 | // Replace The "#include" File Below With The CPU Relevant One For Your Board 18 | #include "stm32f1xx.h" 19 | 20 | // The Number OF Separate DOT MATRIX Units (Whether Single or Cascaded) To Be Used In The Project 21 | #define DOT_MATRIX_UNITS 1 22 | // The Matrix Units Count Of The Longest Cascaded String In The System 23 | #define MAX_CASCADED_NUM 2 24 | 25 | // DOT Matrix SPI Options 26 | #define DOT_MATRIX_SPI SPI1 27 | 28 | // DOT Matrix Timer Base Options 29 | #define MATRIX_TIMER_EN 1 30 | #define MATRIX_TIMER TIM4 31 | #define MATRIX_TIMER_CLK 72 32 | #define MATRIX_TIME_BASE 1 33 | 34 | // DOT Matrix Other Definitions 35 | #define STATIC_MODE 0 36 | #define SCROLL_MODE 1 37 | 38 | // DOT MATRIX Configuration Parameter Structure 39 | typedef struct 40 | { 41 | GPIO_TypeDef * SS_GPIO; 42 | /* 43 | * GPIOA or GPIOB ... 44 | * */ 45 | uint16_t SS_PIN; 46 | /* 47 | * GPIO_PIN_0 or GPIO_PIN_1 ... 48 | * */ 49 | uint16_t SCROLL_SPEED; 50 | /* 51 | * Any Value [0-65535] 52 | * The Bigger This Number, The Slower Scrolling Becomes 53 | * */ 54 | uint8_t CASCADED_DEVICES; 55 | /* 56 | * Any Number of Devices [ 1 - 255 ] 57 | * */ 58 | uint8_t BRIGHTNESS; 59 | /* 60 | * Any Value [ 0 -> 15 ] 61 | * */ 62 | uint8_t SCROLL_Mode; 63 | /* 64 | * STATIC_MODE or SCROLL_MODE 65 | * */ 66 | }DOT_MATRIX_CfgType; 67 | 68 | /*-----[ Prototypes For All Functions ]-----*/ 69 | 70 | // Init Functions Without & With Dedicated Timer 71 | void DOT_MATRIX_Init(SPI_HandleTypeDef * hspi); 72 | void DOT_MATRIX_Init_TMR(SPI_HandleTypeDef * hspi, TIM_HandleTypeDef* TMR_Handle); 73 | // STATOC MODE Functions 74 | void MATRIX_CLEAR(uint8_t au8_MATRIX_Instance); 75 | void MATRIX_Write_Char(uint8_t au8_MATRIX_Instance, uint8_t myChar); 76 | // SCROLL MODE Functions 77 | void DOT_MATRIX_Main(void); 78 | void MATRIX_TMR_OVF_ISR(TIM_HandleTypeDef* htim); 79 | void MATRIX_SCROLL_SetSpeed(uint8_t au8_MATRIX_Instance, uint16_t au16_SPEED); 80 | void MATRIX_DisplayMessage(uint8_t au8_MATRIX_Instance, char* ArrayPointer, uint16_t ArraySize); 81 | 82 | #endif /* DOT_MATRIX_H_ */ 83 | -------------------------------------------------------------------------------- /ECUAL/DOT_MATRIX/DOT_MATRIX_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DOT_MATRIX_cfg.c 3 | * Driver Name: [[ DOT MATRIX MAX7219 ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "DOT_MATRIX.h" 14 | 15 | const DOT_MATRIX_CfgType DOT_MATRIX_CfgParam[DOT_MATRIX_UNITS] = 16 | { 17 | // DOT_MATRIX Display Unit1 Configurations 18 | { 19 | GPIOB, 20 | GPIO_PIN_0, 21 | 75, /* Scroll Speed*/ 22 | 2, /* Number Of Cascaded Devices*/ 23 | 8, /* Brightness Level */ 24 | SCROLL_MODE 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /ECUAL/DOT_MATRIX/DOT_MATRIX_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DOT_MATRIX_cfg.h 3 | * Driver Name: [[ DOT MATRIX MAX7219 ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef DOT_MATRIX_CFG_H_ 14 | #define DOT_MATRIX_CFG_H_ 15 | 16 | #include "DOT_MATRIX.h" 17 | 18 | extern const DOT_MATRIX_CfgType DOT_MATRIX_CfgParam[DOT_MATRIX_UNITS]; 19 | 20 | #endif /* DOT_MATRIX_CFG_H_ */ 21 | -------------------------------------------------------------------------------- /ECUAL/HCSR04/HCSR04.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: HCSR04.c 3 | * Driver Name: [[ HC-SR04 Ultrasonic Sensor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "../HCSR04/HCSR04.h" 14 | 15 | #include "../../util/DWT_Delay.h" 16 | #include "../HCSR04/HCSR04_cfg.h" 17 | 18 | typedef struct 19 | { 20 | uint8_t EDGE_STATE; 21 | uint16_t TMR_OVC; 22 | uint32_t TMR_PSC; 23 | uint32_t TMR_ARR; 24 | uint32_t T1; 25 | uint32_t T2; 26 | uint32_t DIFF; 27 | float DISTANCE; 28 | TIM_HandleTypeDef* HTIM; 29 | HAL_TIM_ActiveChannel ACTIV_CH; 30 | }HCSR04_info; 31 | 32 | static HCSR04_info gs_HCSR04_info[HCSR04_UNITS] = {0}; 33 | 34 | 35 | 36 | void HCSR04_Init(uint8_t au8_HCSR04_Instance, TIM_HandleTypeDef* TMR_Handle) 37 | { 38 | GPIO_InitTypeDef TRIG_GPIO_InitStruct = {0}; 39 | TIM_ClockConfigTypeDef sClockSourceConfig = {0}; 40 | TIM_MasterConfigTypeDef sMasterConfig = {0}; 41 | TIM_IC_InitTypeDef sConfigIC = {0}; 42 | 43 | DWT_Delay_Init(); 44 | 45 | /*--------[ Configure The HCSR04 TRIGGER GPIO Pin ]-------*/ 46 | 47 | if(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO == GPIOA) 48 | { 49 | __HAL_RCC_GPIOA_CLK_ENABLE(); 50 | } 51 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO == GPIOB) 52 | { 53 | __HAL_RCC_GPIOB_CLK_ENABLE(); 54 | } 55 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO == GPIOC) 56 | { 57 | __HAL_RCC_GPIOC_CLK_ENABLE(); 58 | } 59 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO == GPIOD) 60 | { 61 | __HAL_RCC_GPIOD_CLK_ENABLE(); 62 | } 63 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO == GPIOE) 64 | { 65 | __HAL_RCC_GPIOE_CLK_ENABLE(); 66 | } 67 | TRIG_GPIO_InitStruct.Pin = HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_PIN; 68 | TRIG_GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 69 | TRIG_GPIO_InitStruct.Pull = GPIO_NOPULL; 70 | TRIG_GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 71 | HAL_GPIO_Init(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO, &TRIG_GPIO_InitStruct); 72 | 73 | /*--------[ Initialize The HCSR04 Static Global Info ]-------*/ 74 | 75 | gs_HCSR04_info[au8_HCSR04_Instance].TMR_PSC = HCSR04_CfgParam[au8_HCSR04_Instance].TIM_Instance->PSC; 76 | gs_HCSR04_info[au8_HCSR04_Instance].TMR_ARR = HCSR04_CfgParam[au8_HCSR04_Instance].TIM_Instance->ARR; 77 | gs_HCSR04_info[au8_HCSR04_Instance].TMR_OVC = 0; 78 | gs_HCSR04_info[au8_HCSR04_Instance].HTIM = TMR_Handle; 79 | if(gs_HCSR04_info[au8_HCSR04_Instance].TMR_ARR == 0) 80 | { 81 | gs_HCSR04_info[au8_HCSR04_Instance].TMR_ARR = 65535; 82 | } 83 | if(HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH == TIM_CHANNEL_1) 84 | { 85 | gs_HCSR04_info[au8_HCSR04_Instance].ACTIV_CH = HAL_TIM_ACTIVE_CHANNEL_1; 86 | } 87 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH == TIM_CHANNEL_2) 88 | { 89 | gs_HCSR04_info[au8_HCSR04_Instance].ACTIV_CH = HAL_TIM_ACTIVE_CHANNEL_2; 90 | } 91 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH == TIM_CHANNEL_3) 92 | { 93 | gs_HCSR04_info[au8_HCSR04_Instance].ACTIV_CH = HAL_TIM_ACTIVE_CHANNEL_3; 94 | } 95 | else if(HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH == TIM_CHANNEL_4) 96 | { 97 | gs_HCSR04_info[au8_HCSR04_Instance].ACTIV_CH = HAL_TIM_ACTIVE_CHANNEL_4; 98 | } 99 | 100 | /*--------[ Configure The HCSR04 IC Timer Channel ]-------*/ 101 | 102 | TMR_Handle->Instance = HCSR04_CfgParam[au8_HCSR04_Instance].TIM_Instance; 103 | TMR_Handle->Init.Prescaler = gs_HCSR04_info[au8_HCSR04_Instance].TMR_PSC; 104 | TMR_Handle->Init.CounterMode = TIM_COUNTERMODE_UP; 105 | TMR_Handle->Init.Period = gs_HCSR04_info[au8_HCSR04_Instance].TMR_ARR; 106 | TMR_Handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 107 | TMR_Handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; 108 | HAL_TIM_Base_Init(TMR_Handle); 109 | sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 110 | HAL_TIM_ConfigClockSource(TMR_Handle, &sClockSourceConfig); 111 | HAL_TIM_IC_Init(TMR_Handle); 112 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 113 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 114 | HAL_TIMEx_MasterConfigSynchronization(TMR_Handle, &sMasterConfig); 115 | sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; 116 | sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; 117 | sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; 118 | sConfigIC.ICFilter = 0; 119 | HAL_TIM_IC_ConfigChannel(TMR_Handle, &sConfigIC, HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH); 120 | 121 | /*--------[ Start The ICU Channel ]-------*/ 122 | 123 | HAL_TIM_Base_Start_IT(TMR_Handle); 124 | HAL_TIM_IC_Start_IT(TMR_Handle, HCSR04_CfgParam[au8_HCSR04_Instance].IC_TIM_CH); 125 | } 126 | 127 | 128 | void HCSR04_TMR_OVF_ISR(TIM_HandleTypeDef* htim) 129 | { 130 | uint8_t i = 0; 131 | for(i=0; iInstance == HCSR04_CfgParam[i].TIM_Instance) 134 | { 135 | gs_HCSR04_info[i].TMR_OVC++; 136 | } 137 | } 138 | } 139 | 140 | 141 | void HCSR04_TMR_IC_ISR(TIM_HandleTypeDef* htim) 142 | { 143 | uint8_t i = 0; 144 | uint32_t PS = 0; 145 | for(i=0; iInstance == HCSR04_CfgParam[i].TIM_Instance) && (htim->Channel == gs_HCSR04_info[i].ACTIV_CH)) 148 | { 149 | if (gs_HCSR04_info[i].EDGE_STATE == 0) 150 | { 151 | // Capture T1 & Reverse The ICU Edge Polarity 152 | gs_HCSR04_info[i].T1 = HAL_TIM_ReadCapturedValue(htim, HCSR04_CfgParam[i].IC_TIM_CH); 153 | gs_HCSR04_info[i].EDGE_STATE = 1; 154 | __HAL_TIM_SET_CAPTUREPOLARITY(htim, HCSR04_CfgParam[i].IC_TIM_CH, TIM_INPUTCHANNELPOLARITY_FALLING); 155 | gs_HCSR04_info[i].TMR_OVC = 0; 156 | } 157 | else if (gs_HCSR04_info[i].EDGE_STATE == 1) 158 | { 159 | // Read The Current ARR & Prescaler Values For The Timer 160 | PS = HCSR04_CfgParam[i].TIM_Instance->PSC; 161 | gs_HCSR04_info[i].TMR_ARR = HCSR04_CfgParam[i].TIM_Instance->ARR; 162 | // Capture T2 & Calculate The Distance 163 | gs_HCSR04_info[i].T2 = HAL_TIM_ReadCapturedValue(htim, HCSR04_CfgParam[i].IC_TIM_CH); 164 | gs_HCSR04_info[i].T2 += (gs_HCSR04_info[i].TMR_OVC * (gs_HCSR04_info[i].TMR_ARR+1)); 165 | gs_HCSR04_info[i].DIFF = gs_HCSR04_info[i].T2 - gs_HCSR04_info[i].T1; 166 | // Write The Distance Value To The Global Struct & Reverse The ICU Edge 167 | gs_HCSR04_info[i].DISTANCE = (gs_HCSR04_info[i].DIFF * 0.017)/(HCSR04_CfgParam[i].TIM_CLK_MHz/(PS+1)); 168 | gs_HCSR04_info[i].EDGE_STATE = 0; 169 | __HAL_TIM_SET_CAPTUREPOLARITY(htim, HCSR04_CfgParam[i].IC_TIM_CH, TIM_INPUTCHANNELPOLARITY_RISING); 170 | } 171 | } 172 | } 173 | } 174 | 175 | float HCSR04_Read(uint8_t au8_HCSR04_Instance) 176 | { 177 | return gs_HCSR04_info[au8_HCSR04_Instance].DISTANCE; 178 | } 179 | 180 | void HCSR04_Trigger(uint8_t au8_HCSR04_Instance) 181 | { 182 | HAL_GPIO_WritePin(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO, HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_PIN, 1); 183 | DWT_Delay_us(2); 184 | HAL_GPIO_WritePin(HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_GPIO, HCSR04_CfgParam[au8_HCSR04_Instance].TRIG_PIN, 0); 185 | } 186 | -------------------------------------------------------------------------------- /ECUAL/HCSR04/HCSR04.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: HCSR04.h 3 | * Driver Name: [[ HC-SR04 Ultrasonic Sensor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.0 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef HCSR04_H_ 15 | #define HCSR04_H_ 16 | 17 | #define HAL_TIM_MODULE_ENABLED 18 | 19 | #include "stm32f1xx_hal.h" 20 | 21 | 22 | // The Number OF HC-SR04 Ultrasonic Sensors To Be Used In The Project 23 | #define HCSR04_UNITS 1 24 | 25 | typedef struct 26 | { 27 | GPIO_TypeDef * TRIG_GPIO; 28 | uint16_t TRIG_PIN; 29 | TIM_TypeDef* TIM_Instance; 30 | uint32_t IC_TIM_CH; 31 | uint32_t TIM_CLK_MHz; 32 | }HCSR04_CfgType; 33 | 34 | 35 | /*-----[ Prototypes For All Functions ]-----*/ 36 | 37 | void HCSR04_Init(uint8_t au8_HCSR04_Instance, TIM_HandleTypeDef* TMR_Handle); 38 | void HCSR04_Trigger(uint8_t au8_HCSR04_Instance); 39 | void HCSR04_TMR_OVF_ISR(TIM_HandleTypeDef* htim); 40 | void HCSR04_TMR_IC_ISR(TIM_HandleTypeDef* htim); 41 | float HCSR04_Read(uint8_t au8_HCSR04_Instance); 42 | 43 | #endif /* HCSR04_H_ */ 44 | -------------------------------------------------------------------------------- /ECUAL/HCSR04/HCSR04_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: HCSR04_cfg.c 3 | * Driver Name: [[ HC-SR04 Ultrasonic Sensor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "../HCSR04/HCSR04.h" 14 | 15 | const HCSR04_CfgType HCSR04_CfgParam[HCSR04_UNITS] = 16 | { 17 | // HC-SR04 Sensor Unit 1 Configurations 18 | { 19 | GPIOB, 20 | GPIO_PIN_12, 21 | TIM2, 22 | TIM_CHANNEL_1, 23 | 72 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /ECUAL/HCSR04/HCSR04_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: HCSR04_cfg.h 3 | * Driver Name: [[ HC-SR04 Ultrasonic Sensor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef HCSR04_CFG_H_ 14 | #define HCSR04_CFG_H_ 15 | 16 | #include "../HCSR04/HCSR04.h" 17 | 18 | extern const HCSR04_CfgType HCSR04_CfgParam[HCSR04_UNITS]; 19 | 20 | #endif /* HCSR04_CFG_H_ */ 21 | -------------------------------------------------------------------------------- /ECUAL/I2C_LCD/I2C_LCD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: I2C_LCD.c 3 | * Driver Name: [[ I2C_LCD Display ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jan 28, 2024 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "I2C_LCD.h" 14 | #include "I2C_LCD_cfg.h" 15 | #include "../../Util/Util.h" 16 | 17 | /*-----------------------[INTERNAL DEFINITIONS]-----------------------*/ 18 | // CMD 19 | #define LCD_CLEARDISPLAY 0x01 20 | #define LCD_RETURNHOME 0x02 21 | #define LCD_ENTRYMODESET 0x04 22 | #define LCD_DISPLAYCONTROL 0x08 23 | #define LCD_CURSORSHIFT 0x10 24 | #define LCD_FUNCTIONSET 0x20 25 | #define LCD_SETCGRAMADDR 0x40 26 | #define LCD_SETDDRAMADDR 0x80 27 | // DISPLAY ENTRY 28 | #define LCD_ENTRYRIGHT 0x00 29 | #define LCD_ENTRYLEFT 0x02 30 | #define LCD_ENTRYSHIFTINCREMENT 0x01 31 | #define LCD_ENTRYSHIFTDECREMENT 0x00 32 | // DISPLAY CONTROL 33 | #define LCD_DISPLAYON 0x04 34 | #define LCD_DISPLAYOFF 0x00 35 | #define LCD_CURSORON 0x02 36 | #define LCD_CURSOROFF 0x00 37 | #define LCD_BLINKON 0x01 38 | #define LCD_BLINKOFF 0x00 39 | // CURSOR MOTION 40 | #define LCD_DISPLAYMOVE 0x08 41 | #define LCD_CURSORMOVE 0x00 42 | #define LCD_MOVERIGHT 0x04 43 | #define LCD_MOVELEFT 0x00 44 | // FUNCTION SET 45 | #define LCD_8BITMODE 0x10 46 | #define LCD_4BITMODE 0x00 47 | #define LCD_2LINE 0x08 48 | #define LCD_1LINE 0x00 49 | #define LCD_5x10DOTS 0x04 50 | #define LCD_5x8DOTS 0x00 51 | // BACKLIGHT CONTROL 52 | #define LCD_BACKLIGHT 0x08 53 | #define LCD_NOBACKLIGHT 0x00 54 | #define EN 0b00000100 // Enable bit 55 | #define RW 0b00000010 // Read/Write bit 56 | #define RS 0b00000001 // Register select bit 57 | 58 | /*-----------------------[INTERNAL VARIABLES]-----------------------*/ 59 | 60 | typedef struct I2C_LCD_InfoParam_s 61 | { 62 | uint8_t DisplayCtrl; 63 | uint8_t BacklightVal; 64 | }I2C_LCD_InfoParam_t; 65 | 66 | static I2C_LCD_InfoParam_t I2C_LCD_InfoParam_g[I2C_LCD_MAX]; 67 | 68 | /*---------------------[STATIC INTERNAL FUNCTIONS]-----------------------*/ 69 | 70 | static void I2C_LCD_ExpanderWrite(uint8_t I2C_LCD_InstanceIndex, uint8_t DATA) 71 | { 72 | uint8_t TxData = (DATA) | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].BacklightVal; 73 | HAL_I2C_Master_Transmit(I2C_LCD_CfgParam[I2C_LCD_InstanceIndex].I2C_Handle, (I2C_LCD_CfgParam[I2C_LCD_InstanceIndex].I2C_LCD_Address<<1), &TxData, sizeof(TxData), 100); 74 | } 75 | 76 | static void I2C_LCD_EnPulse(uint8_t I2C_LCD_InstanceIndex, uint8_t DATA) 77 | { 78 | I2C_LCD_ExpanderWrite(I2C_LCD_InstanceIndex, (DATA | EN)); // En high 79 | DELAY_US(2); // enable pulse must be >450ns 80 | 81 | I2C_LCD_ExpanderWrite(I2C_LCD_InstanceIndex, (DATA & ~EN)); // En low 82 | DELAY_US(50); // commands need > 37us to settle 83 | } 84 | 85 | static void I2C_LCD_Write4Bits(uint8_t I2C_LCD_InstanceIndex, uint8_t Val) 86 | { 87 | I2C_LCD_ExpanderWrite(I2C_LCD_InstanceIndex, Val); 88 | I2C_LCD_EnPulse(I2C_LCD_InstanceIndex, Val); 89 | } 90 | 91 | static void I2C_LCD_Send(uint8_t I2C_LCD_InstanceIndex, uint8_t Val, uint8_t Mode) 92 | { 93 | uint8_t HighNib = Val & 0xF0; 94 | uint8_t LowNib = (Val << 4) & 0xF0; 95 | I2C_LCD_Write4Bits(I2C_LCD_InstanceIndex, (HighNib) | Mode); 96 | I2C_LCD_Write4Bits(I2C_LCD_InstanceIndex, (LowNib) | Mode); 97 | } 98 | 99 | static void I2C_LCD_Cmd(uint8_t I2C_LCD_InstanceIndex, uint8_t CMD) 100 | { 101 | I2C_LCD_Send(I2C_LCD_InstanceIndex, CMD, 0); 102 | } 103 | 104 | static void I2C_LCD_Data(uint8_t I2C_LCD_InstanceIndex, uint8_t DATA) 105 | { 106 | I2C_LCD_Send(I2C_LCD_InstanceIndex, DATA, 1); 107 | } 108 | 109 | /*-----------------------------------------------------------------------*/ 110 | 111 | //========================================================================================================================= 112 | 113 | /*-----------------------[USER EXTERNAL FUNCTIONS]-----------------------*/ 114 | 115 | void I2C_LCD_Init(uint8_t I2C_LCD_InstanceIndex) 116 | { 117 | // According To Datasheet, We Must Wait At Least 40ms After Power Up Before Interacting With The LCD Module 118 | while(HAL_GetTick() < 50); 119 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, 0x30); 120 | DELAY_MS(5); // Delay > 4.1ms 121 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, 0x30); 122 | DELAY_MS(5); // Delay > 4.1ms 123 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, 0x30); 124 | DELAY_US(150); // Delay > 100μs 125 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, 0x02); 126 | // Configure the LCD 127 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS); 128 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF); 129 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT); 130 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; 131 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].BacklightVal = LCD_BACKLIGHT; 132 | // Clear the LCD 133 | I2C_LCD_Clear(I2C_LCD_InstanceIndex); 134 | } 135 | 136 | void I2C_LCD_Clear(uint8_t I2C_LCD_InstanceIndex) 137 | { 138 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_CLEARDISPLAY); 139 | DELAY_MS(2); 140 | } 141 | 142 | void I2C_LCD_Home(uint8_t I2C_LCD_InstanceIndex) 143 | { 144 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_RETURNHOME); 145 | DELAY_MS(2); 146 | } 147 | 148 | void I2C_LCD_SetCursor(uint8_t I2C_LCD_InstanceIndex, uint8_t Col, uint8_t Row) 149 | { 150 | int Row_Offsets[] = {0x00, 0x40, 0x14, 0x54}; 151 | if (Row > I2C_LCD_CfgParam[I2C_LCD_InstanceIndex].I2C_LCD_nRow) 152 | { 153 | Row = I2C_LCD_CfgParam[I2C_LCD_InstanceIndex].I2C_LCD_nRow - 1; 154 | } 155 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_SETDDRAMADDR | (Col + Row_Offsets[Row])); 156 | } 157 | 158 | void I2C_LCD_WriteChar(uint8_t I2C_LCD_InstanceIndex, char Ch) 159 | { 160 | I2C_LCD_Data(I2C_LCD_InstanceIndex, Ch); 161 | } 162 | 163 | void I2C_LCD_WriteString(uint8_t I2C_LCD_InstanceIndex, char *Str) 164 | { 165 | while (*Str) 166 | { 167 | I2C_LCD_Data(I2C_LCD_InstanceIndex, *Str++); 168 | } 169 | } 170 | 171 | void I2C_LCD_ShiftLeft(uint8_t I2C_LCD_InstanceIndex) 172 | { 173 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); 174 | } 175 | 176 | void I2C_LCD_ShiftRight(uint8_t I2C_LCD_InstanceIndex) 177 | { 178 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); 179 | } 180 | 181 | void I2C_LCD_Backlight(uint8_t I2C_LCD_InstanceIndex) 182 | { 183 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].BacklightVal = LCD_BACKLIGHT; 184 | I2C_LCD_ExpanderWrite(I2C_LCD_InstanceIndex, 0); 185 | } 186 | 187 | void I2C_LCD_NoBacklight(uint8_t I2C_LCD_InstanceIndex) 188 | { 189 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].BacklightVal = LCD_NOBACKLIGHT; 190 | I2C_LCD_ExpanderWrite(I2C_LCD_InstanceIndex, 0); 191 | } 192 | 193 | void I2C_LCD_Display(uint8_t I2C_LCD_InstanceIndex) 194 | { 195 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl |= LCD_DISPLAYON; 196 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 197 | } 198 | 199 | void I2C_LCD_NoDisplay(uint8_t I2C_LCD_InstanceIndex) 200 | { 201 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl &= ~LCD_DISPLAYON; 202 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 203 | } 204 | 205 | void I2C_LCD_Cursor(uint8_t I2C_LCD_InstanceIndex) 206 | { 207 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl |= LCD_CURSORON; 208 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 209 | } 210 | 211 | void I2C_LCD_NoCursor(uint8_t I2C_LCD_InstanceIndex) 212 | { 213 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl &= ~LCD_CURSORON; 214 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 215 | } 216 | 217 | void I2C_LCD_Blink(uint8_t I2C_LCD_InstanceIndex) 218 | { 219 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl |= LCD_BLINKON; 220 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 221 | } 222 | 223 | void I2C_LCD_NoBlink(uint8_t I2C_LCD_InstanceIndex) 224 | { 225 | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl &= ~LCD_BLINKON; 226 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_DISPLAYCONTROL | I2C_LCD_InfoParam_g[I2C_LCD_InstanceIndex].DisplayCtrl); 227 | } 228 | 229 | void I2C_LCD_CreateCustomChar(uint8_t I2C_LCD_InstanceIndex, uint8_t CharIndex, const uint8_t* CharMap) 230 | { 231 | CharIndex &= 0x07; 232 | I2C_LCD_Cmd(I2C_LCD_InstanceIndex, LCD_SETCGRAMADDR | (CharIndex << 3)); 233 | for (int i = 0; i < 8; i++) 234 | { 235 | I2C_LCD_Send(I2C_LCD_InstanceIndex, CharMap[i], RS); 236 | } 237 | } 238 | 239 | void I2C_LCD_PrintCustomChar(uint8_t I2C_LCD_InstanceIndex, uint8_t CharIndex) 240 | { 241 | I2C_LCD_Send(I2C_LCD_InstanceIndex, CharIndex, RS); 242 | } 243 | -------------------------------------------------------------------------------- /ECUAL/I2C_LCD/I2C_LCD.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: I2C_LCD.h 3 | * Driver Name: [[ I2C_LCD Display ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jan 28, 2024 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef I2C_LCD_H_ 14 | #define I2C_LCD_H_ 15 | 16 | #include "stdint.h" 17 | 18 | #define I2C_LCD_MAX 1 // Maximum Number of I2C_LCD Modules in Your Project 19 | #define I2C_LCD_1 0 // I2C_LCD Instance Number 1 (Add more if you need) 20 | 21 | //-----[ Prototypes For All User External Functions ]----- 22 | 23 | void I2C_LCD_Init(uint8_t I2C_LCD_InstanceIndex); 24 | void I2C_LCD_Clear(uint8_t I2C_LCD_InstanceIndex); 25 | void I2C_LCD_Home(uint8_t I2C_LCD_InstanceIndex); 26 | void I2C_LCD_SetCursor(uint8_t I2C_LCD_InstanceIndex, uint8_t Col, uint8_t Row); 27 | void I2C_LCD_WriteChar(uint8_t I2C_LCD_InstanceIndex, char Ch); 28 | void I2C_LCD_WriteString(uint8_t I2C_LCD_InstanceIndex, char* Str); 29 | 30 | void I2C_LCD_ShiftLeft(uint8_t I2C_LCD_InstanceIndex); 31 | void I2C_LCD_ShiftRight(uint8_t I2C_LCD_InstanceIndex); 32 | 33 | void I2C_LCD_Backlight(uint8_t I2C_LCD_InstanceIndex); 34 | void I2C_LCD_NoBacklight(uint8_t I2C_LCD_InstanceIndex); 35 | void I2C_LCD_Display(uint8_t I2C_LCD_InstanceIndex); 36 | void I2C_LCD_NoDisplay(uint8_t I2C_LCD_InstanceIndex); 37 | void I2C_LCD_Cursor(uint8_t I2C_LCD_InstanceIndex); 38 | void I2C_LCD_NoCursor(uint8_t I2C_LCD_InstanceIndex); 39 | void I2C_LCD_Blink(uint8_t I2C_LCD_InstanceIndex); 40 | void I2C_LCD_NoBlink(uint8_t I2C_LCD_InstanceIndex); 41 | 42 | void I2C_LCD_CreateCustomChar(uint8_t I2C_LCD_InstanceIndex, uint8_t CharIndex, const uint8_t* CharMap); 43 | void I2C_LCD_PrintCustomChar(uint8_t I2C_LCD_InstanceIndex, uint8_t CharIndex); 44 | 45 | #endif /* I2C_LCD_H_ */ 46 | -------------------------------------------------------------------------------- /ECUAL/I2C_LCD/I2C_LCD_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: I2C_LCD_cfg.c 3 | * Driver Name: [[ I2C_LCD Display ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jan 28, 2024 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "I2C_LCD_cfg.h" 14 | #include "I2C_LCD.h" 15 | 16 | extern I2C_HandleTypeDef hi2c1; 17 | 18 | const I2C_LCD_CfgType I2C_LCD_CfgParam[I2C_LCD_MAX] = 19 | { 20 | { /* Configuration Parameter For I2C_LCD Instance #1 */ 21 | I2C_LCD_1, /* Index of I2C_LCD Instance #1 */ 22 | &hi2c1, /* Hardware I2C Module's Handle */ 23 | 0x27, /* Hardware I2C_LCD Device Address */ 24 | 16, /* LCD Columns Count */ 25 | 2 /* LCD Rows Count */ 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /ECUAL/I2C_LCD/I2C_LCD_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: I2C_LCD_cfg.h 3 | * Driver Name: [[ I2C_LCD Display ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jan 28, 2024 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef I2C_LCD_CFG_H_ 14 | #define I2C_LCD_CFG_H_ 15 | 16 | #include "main.h" 17 | #include "I2C_LCD.h" 18 | 19 | typedef struct 20 | { 21 | // I2C LCD Module Instance Index 22 | uint8_t I2C_LCD_Instance; 23 | 24 | // I2C Hardware Peripheral Handle 25 | I2C_HandleTypeDef* I2C_Handle; 26 | 27 | // I2C LCD Hardware Device Address 28 | uint8_t I2C_LCD_Address; 29 | 30 | // I2C LCD Columns Count 31 | uint8_t I2C_LCD_nCol; 32 | 33 | // I2C LCD Rows Count 34 | uint8_t I2C_LCD_nRow; 35 | 36 | }I2C_LCD_CfgType; 37 | 38 | extern const I2C_LCD_CfgType I2C_LCD_CfgParam[I2C_LCD_MAX]; 39 | 40 | #endif /* I2C_LCD_CFG_H_ */ 41 | -------------------------------------------------------------------------------- /ECUAL/JOYSTICK/JOYSTICK.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: JOYSTICK.c 3 | * Driver Name: [[ JoyStick ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "JOYSTICK.h" 14 | #include "JOYSTICK_cfg.h" 15 | 16 | static ADC_HandleTypeDef hadc[JOYSTICK_UNITS] = {0}; 17 | static ADC_ChannelConfTypeDef sConfig = {0}; 18 | static uint8_t calibrated = 0; 19 | 20 | void JoyStick_Init(uint16_t JoyStick_Instance) 21 | { 22 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 23 | 24 | if(JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO == GPIOA || JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO == GPIOA) 25 | { 26 | __HAL_RCC_GPIOA_CLK_ENABLE(); 27 | } 28 | else if(JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO == GPIOB || JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO == GPIOB) 29 | { 30 | __HAL_RCC_GPIOB_CLK_ENABLE(); 31 | } 32 | else if(JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO == GPIOC || JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO == GPIOC) 33 | { 34 | __HAL_RCC_GPIOC_CLK_ENABLE(); 35 | } 36 | else if (JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO == GPIOD || JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO == GPIOD) 37 | { 38 | __HAL_RCC_GPIOD_CLK_ENABLE(); 39 | } 40 | else if (JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO == GPIOE || JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO == GPIOE) 41 | { 42 | __HAL_RCC_GPIOD_CLK_ENABLE(); 43 | } 44 | 45 | GPIO_InitStruct.Pin = JoyStick_CfgParam[JoyStick_Instance].JoyStick_xPIN; 46 | GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; 47 | HAL_GPIO_Init(JoyStick_CfgParam[JoyStick_Instance].JoyStick_xGPIO, &GPIO_InitStruct); 48 | 49 | GPIO_InitStruct.Pin = JoyStick_CfgParam[JoyStick_Instance].JoyStick_yPIN; 50 | GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; 51 | HAL_GPIO_Init(JoyStick_CfgParam[JoyStick_Instance].JoyStick_yGPIO, &GPIO_InitStruct); 52 | 53 | hadc[JoyStick_Instance].Instance = JoyStick_CfgParam[JoyStick_Instance].ADC_Instance; 54 | hadc[JoyStick_Instance].Init.ScanConvMode = ADC_SCAN_DISABLE; 55 | hadc[JoyStick_Instance].Init.ContinuousConvMode = DISABLE; 56 | hadc[JoyStick_Instance].Init.DiscontinuousConvMode = DISABLE; 57 | hadc[JoyStick_Instance].Init.ExternalTrigConv = ADC_SOFTWARE_START; 58 | hadc[JoyStick_Instance].Init.DataAlign = ADC_DATAALIGN_RIGHT; 59 | hadc[JoyStick_Instance].Init.NbrOfConversion = 1; 60 | HAL_ADC_Init(&hadc[JoyStick_Instance]); 61 | sConfig.Channel = JoyStick_CfgParam[JoyStick_Instance].ADCx_CH; 62 | sConfig.Rank = ADC_REGULAR_RANK_1; 63 | sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; 64 | HAL_ADC_ConfigChannel(&hadc[JoyStick_Instance], &sConfig); 65 | 66 | if(calibrated == 0) 67 | { 68 | HAL_ADCEx_Calibration_Start(&hadc[JoyStick_Instance]); 69 | calibrated = 1; 70 | } 71 | } 72 | 73 | 74 | void JoyStick_Read(uint16_t JoyStick_Instance, uint16_t* JoyStick_XY) 75 | { 76 | uint32_t AD_RES; 77 | 78 | // Select The JoyStick Instance ADC Channel For X 79 | sConfig.Channel = JoyStick_CfgParam[JoyStick_Instance].ADCx_CH; 80 | HAL_ADC_ConfigChannel(&hadc[JoyStick_Instance], &sConfig); 81 | // Start ADC Conversion 82 | HAL_ADC_Start(&hadc[JoyStick_Instance]); 83 | // Poll ADC1 Peripheral & TimeOut = 1mSec 84 | HAL_ADC_PollForConversion(&hadc[JoyStick_Instance], 1); 85 | // Read The ADC Conversion Result Write It To JoyStick X 86 | AD_RES = HAL_ADC_GetValue(&hadc[JoyStick_Instance]); 87 | JoyStick_XY[0] = AD_RES; 88 | 89 | // Select The JoyStick Instance ADC Channel For Y 90 | sConfig.Channel = JoyStick_CfgParam[JoyStick_Instance].ADCy_CH; 91 | HAL_ADC_ConfigChannel(&hadc[JoyStick_Instance], &sConfig); 92 | // Start ADC Conversion 93 | HAL_ADC_Start(&hadc[JoyStick_Instance]); 94 | // Poll ADC1 Peripheral & TimeOut = 1mSec 95 | HAL_ADC_PollForConversion(&hadc[JoyStick_Instance], 1); 96 | // Read The ADC Conversion Result Write It To JoyStick Y 97 | AD_RES = HAL_ADC_GetValue(&hadc[JoyStick_Instance]); 98 | JoyStick_XY[1] = AD_RES; 99 | } 100 | -------------------------------------------------------------------------------- /ECUAL/JOYSTICK/JOYSTICK.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: JOYSTICK.h 3 | * Driver Name: [[ JoyStick ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.0 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef JOYSTICK_H_ 15 | #define JOYSTICK_H_ 16 | 17 | #define HAL_ADC_MODULE_ENABLED 18 | 19 | #include "stm32f1xx_hal.h" 20 | 21 | // The Number OF JoySticks To Be Used In The Project 22 | #define JOYSTICK_UNITS 1 23 | 24 | typedef struct 25 | { 26 | GPIO_TypeDef * JoyStick_xGPIO; 27 | GPIO_TypeDef * JoyStick_yGPIO; 28 | uint16_t JoyStick_xPIN; 29 | uint16_t JoyStick_yPIN; 30 | ADC_TypeDef* ADC_Instance; 31 | uint32_t ADCx_CH; 32 | uint32_t ADCy_CH; 33 | }JoyStick_CfgType; 34 | 35 | 36 | /*-----[ Prototypes For All Functions ]-----*/ 37 | void JoyStick_Init(uint16_t JoyStick_Instance); 38 | void JoyStick_Read(uint16_t JoyStick_Instance, uint16_t* JoyStick_XY); 39 | 40 | #endif /* JOYSTICK_H_ */ 41 | -------------------------------------------------------------------------------- /ECUAL/JOYSTICK/JOYSTICK_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: JOYSTICK_cfg.c 3 | * Driver Name: [[ JoyStick ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | #include "JOYSTICK.h" 13 | 14 | const JoyStick_CfgType JoyStick_CfgParam[JOYSTICK_UNITS] = 15 | { 16 | // JoyStick unit 1 Configurations 17 | { 18 | GPIOA, 19 | GPIOA, 20 | GPIO_PIN_6, 21 | GPIO_PIN_7, 22 | ADC1, 23 | ADC_CHANNEL_6, 24 | ADC_CHANNEL_7 25 | } 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /ECUAL/JOYSTICK/JOYSTICK_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: JOYSTICK_cfg.h 3 | * Driver Name: [[ JoyStick ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef JOYSTICK_CFG_H_ 14 | #define JOYSTICK_CFG_H_ 15 | 16 | 17 | #include "JOYSTICK.h" 18 | 19 | extern const JoyStick_CfgType JoyStick_CfgParam[JOYSTICK_UNITS]; 20 | 21 | #endif /* JOYSTICK_CFG_H_ */ 22 | -------------------------------------------------------------------------------- /ECUAL/KEYPAD/KEYPAD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: KEYPAD.c 3 | * Driver Name: [[ 4x4 KEYPAD ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "KEYPAD.h" 14 | #include "KEYPAD_cfg.h" 15 | 16 | 17 | typedef struct 18 | { 19 | uint8_t* KEY_States; 20 | }KEYPAD_info; 21 | 22 | static KEYPAD_info gs_KEYPAD_info[KEYPAD_UNITS] = {0}; 23 | 24 | 25 | 26 | void KEYPAD_Init(uint16_t au16_Instance, uint8_t* au8_KeyStates) 27 | { 28 | uint8_t i = 0; 29 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 30 | 31 | if(au8_KeyStates != NULL) 32 | { 33 | gs_KEYPAD_info[au16_Instance].KEY_States = au8_KeyStates; 34 | } 35 | else 36 | { 37 | /* Potentially Should Return An Error */ 38 | return; 39 | } 40 | /*--------[ Configure The KeyPAD ROWs GPIO Pins ]-------*/ 41 | for(i=0; i> 4; 68 | Low4 = Temp & 0x0F; 69 | LCD16X2_CMD(LCD16X2_Index, High4); 70 | LCD16X2_CMD(LCD16X2_Index, Low4); 71 | } 72 | if(r == 2) 73 | { 74 | Temp = 0xC0 + c - 1; 75 | High4 = Temp >> 4; 76 | Low4 = Temp & 0x0F; 77 | LCD16X2_CMD(LCD16X2_Index, High4); 78 | LCD16X2_CMD(LCD16X2_Index, Low4); 79 | } 80 | } 81 | 82 | void LCD16X2_Init(uint8_t LCD16X2_Index) 83 | { 84 | // According To Datasheet, We Must Wait At Least 40ms After Power Up Before Interacting With The LCD Module 85 | while(HAL_GetTick() < 50); 86 | // The Init. Procedure As Described In The Datasheet 87 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].RS_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].RS_PINx, 0); 88 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 0); 89 | // Init in 4-Bit Data Mode 90 | LCD16X2_DATA(LCD16X2_Index, 0x00); 91 | DELAY_MS(150); 92 | LCD16X2_CMD(LCD16X2_Index, 0x03); 93 | DELAY_MS(5); 94 | LCD16X2_CMD(LCD16X2_Index, 0x03); 95 | DELAY_MS(5); 96 | LCD16X2_CMD(LCD16X2_Index, 0x03); 97 | DELAY_US(150); 98 | // The Rest of The Init Sequence As Defined in The Hitachi HD44780 Datasheet 99 | LCD16X2_CMD(LCD16X2_Index, 0x02); 100 | LCD16X2_CMD(LCD16X2_Index, 0x02); 101 | LCD16X2_CMD(LCD16X2_Index, 0x08); 102 | LCD16X2_CMD(LCD16X2_Index, 0x00); 103 | LCD16X2_CMD(LCD16X2_Index, 0x0C); 104 | LCD16X2_CMD(LCD16X2_Index, 0x00); 105 | LCD16X2_CMD(LCD16X2_Index, 0x06); 106 | LCD16X2_CMD(LCD16X2_Index, 0x00); 107 | LCD16X2_CMD(LCD16X2_Index, 0x01); 108 | } 109 | 110 | void LCD16X2_Write_Char(uint8_t LCD16X2_Index, char Data) 111 | { 112 | char Low4,High4; 113 | Low4 = Data & 0x0F; 114 | High4 = Data & 0xF0; 115 | 116 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].RS_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].RS_PINx, 1); 117 | 118 | LCD16X2_DATA(LCD16X2_Index, (High4>>4)); 119 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 0); 120 | DELAY_US(5); 121 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 1); 122 | DELAY_US(5); 123 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 0); 124 | DELAY_US(100); 125 | 126 | LCD16X2_DATA(LCD16X2_Index, Low4); 127 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 0); 128 | DELAY_US(5); 129 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 1); 130 | DELAY_US(5); 131 | HAL_GPIO_WritePin(LCD16X2_CfgParam[LCD16X2_Index].EN_GPIOx, LCD16X2_CfgParam[LCD16X2_Index].EN_PINx, 0); 132 | DELAY_US(100); 133 | } 134 | 135 | void LCD16X2_Write_String(uint8_t LCD16X2_Index, char *str) 136 | { 137 | int i; 138 | for(i=0; str[i]!='\0'; i++) 139 | { 140 | LCD16X2_Write_Char(LCD16X2_Index, str[i]); 141 | } 142 | } 143 | 144 | void LCD16X2_SL(uint8_t LCD16X2_Index) 145 | { 146 | LCD16X2_CMD(LCD16X2_Index, 0x01); 147 | LCD16X2_CMD(LCD16X2_Index, 0x08); 148 | } 149 | 150 | void LCD16X2_SR(uint8_t LCD16X2_Index) 151 | { 152 | LCD16X2_CMD(LCD16X2_Index, 0x01); 153 | LCD16X2_CMD(LCD16X2_Index, 0x0C); 154 | } 155 | -------------------------------------------------------------------------------- /ECUAL/LCD16X2/LCD16X2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: LCD16X2.h 3 | * Driver Name: [[ LCD16X2 Display (GPIO 4-Bit Mode) ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.1 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef LCD16X2_H_ 15 | #define LCD16X2_H_ 16 | 17 | #include "stdint.h" 18 | 19 | #define LCD16X2_MAX 1 // Maximum Number of LCD16x2 Modules in Your Project 20 | #define LCD16X2_1 0 // LCD16X2 Instance Number 1 (Add more if you need) 21 | 22 | 23 | //-----[ Prototypes For All Functions ]----- 24 | 25 | extern void LCD16X2_Init(uint8_t); // Initialize The LCD For 4-Bit Interface 26 | extern void LCD16X2_Clear(uint8_t); // Clear The LCD Display 27 | 28 | extern void LCD16X2_Set_Cursor(uint8_t, unsigned char, unsigned char); // Set Cursor Position 29 | 30 | extern void LCD16X2_Write_Char(uint8_t, char); // Write Character To LCD At Current Position 31 | extern void LCD16X2_Write_String(uint8_t, char*); // Write A String To LCD 32 | 33 | extern void LCD16X2_SL(uint8_t); // Shift The Entire Display To The Left 34 | extern void LCD16X2_SR(uint8_t); // Shift The Entire Display To The Right 35 | 36 | #endif /* LCD16X2_H_ */ 37 | -------------------------------------------------------------------------------- /ECUAL/LCD16X2/LCD16X2_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: LCD16X2_cfg.c 3 | * Driver Name: [[ LCD16X2 Display (GPIO 4-Bit Mode) ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "LCD16X2_cfg.h" 14 | #include "LCD16X2.h" 15 | 16 | const LCD16X2_CfgType LCD16X2_CfgParam[LCD16X2_MAX] = 17 | { 18 | { /* Configuration Parameter For LCD Instance #1 */ 19 | LCD16X2_1, /* Index of LCD Instance #1 */ 20 | GPIOA, GPIO_PIN_2, /* LCD D4 Pin GPIO Port & Pin */ 21 | GPIOA, GPIO_PIN_3, /* LCD D5 Pin GPIO Port & Pin */ 22 | GPIOA, GPIO_PIN_4, /* LCD D6 Pin GPIO Port & Pin */ 23 | GPIOA, GPIO_PIN_5, /* LCD D7 Pin GPIO Port & Pin */ 24 | GPIOA, GPIO_PIN_6, /* LCD EN Pin GPIO Port & Pin */ 25 | GPIOA, GPIO_PIN_7 /* LCD RS Pin GPIO Port & Pin */ 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /ECUAL/LCD16X2/LCD16X2_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: LCD16X2_cfg.h 3 | * Driver Name: [[ LCD16X2 Display (GPIO 4-Bit Mode) ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef LCD16X2_CFG_H_ 14 | #define LCD16X2_CFG_H_ 15 | 16 | #include "main.h" 17 | #include "LCD16X2.h" 18 | 19 | typedef struct 20 | { 21 | // LCD Module Instance Index 22 | uint8_t LCD16X2_Instance; 23 | 24 | // LCD Pin: D4 25 | GPIO_TypeDef * D4_GPIOx; 26 | uint16_t D4_PINx; 27 | 28 | // LCD Pin: D5 29 | GPIO_TypeDef * D5_GPIOx; 30 | uint16_t D5_PINx; 31 | 32 | // LCD Pin: D6 33 | GPIO_TypeDef * D6_GPIOx; 34 | uint16_t D6_PINx; 35 | 36 | // LCD Pin: D7 37 | GPIO_TypeDef * D7_GPIOx; 38 | uint16_t D7_PINx; 39 | 40 | // LCD Pin: EN 41 | GPIO_TypeDef * EN_GPIOx; 42 | uint16_t EN_PINx; 43 | 44 | // LCD Pin: RS 45 | GPIO_TypeDef * RS_GPIOx; 46 | uint16_t RS_PINx; 47 | 48 | }LCD16X2_CfgType; 49 | 50 | extern const LCD16X2_CfgType LCD16X2_CfgParam[LCD16X2_MAX]; 51 | 52 | #endif /* LCD16X2_CFG_H_ */ 53 | -------------------------------------------------------------------------------- /ECUAL/LEDS/LEDS.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: LEDS.c 3 | * Driver Name: [[ LEDs Driver ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | 14 | #include "LEDS.h" 15 | #include "LEDS_cfg.h" 16 | 17 | 18 | 19 | void LEDs_Init(void) 20 | { 21 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 22 | uint8_t i = 0; 23 | 24 | for(i=0; i= gs_SERVO_info[au16_SERVO_Instance].Period_Min) 134 | { 135 | *(SERVO_CfgParam[au16_SERVO_Instance].TIM_CCRx) = au16_Pulse; 136 | } 137 | } 138 | 139 | /* Gets The Maximum Pulse Width Value For A Specific Motor */ 140 | uint16_t SERVO_Get_MaxPulse(uint16_t au16_SERVO_Instance) 141 | { 142 | return (gs_SERVO_info[au16_SERVO_Instance].Period_Max); 143 | } 144 | 145 | 146 | /* Gets The Minimum Pulse Width Value For A Specific Motor */ 147 | uint16_t SERVO_Get_MinPulse(uint16_t au16_SERVO_Instance) 148 | { 149 | return (gs_SERVO_info[au16_SERVO_Instance].Period_Min); 150 | } 151 | 152 | 153 | /* Move A Motor From 0 deg to 180 And Back to 0 again */ 154 | void SERVO_Sweep(uint16_t au16_SERVO_Instance) 155 | { 156 | uint8_t au8_Angle = 0; 157 | 158 | SERVO_MoveTo(au16_SERVO_Instance, 0); 159 | 160 | DWT_Delay_ms(250); 161 | while(au8_Angle < 180) 162 | { 163 | SERVO_MoveTo(au16_SERVO_Instance, au8_Angle++); 164 | DWT_Delay_ms(5); 165 | } 166 | DWT_Delay_ms(250); 167 | while(au8_Angle > 0) 168 | { 169 | SERVO_MoveTo(au16_SERVO_Instance, au8_Angle--); 170 | DWT_Delay_ms(5); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /ECUAL/SERVO/SERVO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SERVO.h 3 | * Driver Name: [[ SERVO Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.0 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef SERVO_H_ 15 | #define SERVO_H_ 16 | 17 | #define HAL_TIM_MODULE_ENABLED 18 | 19 | #include "stm32f1xx_hal.h" 20 | 21 | 22 | // The Number OF Servo Motors To Be Used In The Project 23 | #define SERVO_NUM 1 24 | 25 | typedef struct 26 | { 27 | GPIO_TypeDef * SERVO_GPIO; 28 | uint16_t SERVO_PIN; 29 | TIM_TypeDef* TIM_Instance; 30 | uint32_t* TIM_CCRx; 31 | uint32_t PWM_TIM_CH; 32 | uint32_t TIM_CLK; 33 | float MinPulse; 34 | float MaxPulse; 35 | }SERVO_CfgType; 36 | 37 | 38 | /*-----[ Prototypes For All Functions ]-----*/ 39 | 40 | void SERVO_Init(uint16_t au16_SERVO_Instance); 41 | void SERVO_MoveTo(uint16_t au16_SERVO_Instance, float af_Angle); 42 | void SERVO_RawMove(uint16_t au16_SERVO_Instance, uint16_t au16_Pulse); 43 | uint16_t SERVO_Get_MaxPulse(uint16_t au16_SERVO_Instance); 44 | uint16_t SERVO_Get_MinPulse(uint16_t au16_SERVO_Instance); 45 | void SERVO_Sweep(uint16_t au16_SERVO_Instance); 46 | 47 | 48 | #endif /* SERVO_H_ */ 49 | -------------------------------------------------------------------------------- /ECUAL/SERVO/SERVO_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SERVO_cfg.c 3 | * Driver Name: [[ SERVO Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "SERVO.h" 14 | 15 | const SERVO_CfgType SERVO_CfgParam[SERVO_NUM] = 16 | { 17 | // Servo Motor 1 Configurations 18 | { 19 | GPIOA, 20 | GPIO_PIN_0, 21 | TIM2, 22 | &TIM2->CCR1, 23 | TIM_CHANNEL_1, 24 | 72000000, 25 | 0.65, 26 | 2.3 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /ECUAL/SERVO/SERVO_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SERVO_cfg.h 3 | * Driver Name: [[ SERVO Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef SERVO_CFG_H_ 14 | #define SERVO_CFG_H_ 15 | 16 | #include "SERVO.h" 17 | 18 | extern const SERVO_CfgType SERVO_CfgParam[SERVO_NUM]; 19 | 20 | #endif /* SERVO_CFG_H_ */ 21 | -------------------------------------------------------------------------------- /ECUAL/SEVEN_SEGMENTS/SEVEN_SEGMENTS.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SEVEN_SEGMENTS.c 3 | * Driver Name: [[ 7-Segments Display ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "SEVEN_SEGMENTS.h" 14 | #include "SEVEN_SEGMENTS_cfg.h" 15 | 16 | 17 | #define MAX_DIGITS 4 18 | #define ENABLED 1 19 | #define DISABLED 0 20 | 21 | typedef struct 22 | { 23 | uint8_t EN_State; 24 | uint8_t Digits[MAX_DIGITS]; 25 | uint8_t Digit_Index; 26 | }SEVENSEG_info; 27 | 28 | static SEVENSEG_info gs_SEVENSEG_info[SEVEN_SEG_UNITS] = {0}; 29 | 30 | volatile static uint8_t gau8_SevGegPattern[10][7] = 31 | { 32 | /* a b c d e f g */ 33 | {1, 1, 1, 1, 1, 1, 0}, /* Zero */ 34 | {0, 1, 1, 0, 0, 0, 0}, /* One */ 35 | {1, 1, 0, 1, 1, 0, 1}, /* Two */ 36 | {1, 1, 1, 1, 0, 0, 1}, /* Three */ 37 | {0, 1, 1, 0, 0, 1, 1}, /* Four */ 38 | {1, 0, 1, 1, 0, 1, 1}, /* Five */ 39 | {1, 0, 1, 1, 1, 1, 1}, /* Six */ 40 | {1, 1, 1, 0, 0, 0, 0}, /* Seven */ 41 | {1, 1, 1, 1, 1, 1, 1}, /* Eight */ 42 | {1, 1, 1, 1, 0, 1, 1} /* Nine */ 43 | }; 44 | 45 | 46 | 47 | 48 | void SEVEN_SEG_Init(uint16_t au16_Instance) 49 | { 50 | uint8_t i = 0; 51 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 52 | 53 | /*--------[ Configure The 7-Segments GPIO Pins ]-------*/ 54 | for(i=0; i<7; i++) 55 | { 56 | if(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i] == GPIOA) 57 | { 58 | __HAL_RCC_GPIOA_CLK_ENABLE(); 59 | } 60 | else if(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i] == GPIOB) 61 | { 62 | __HAL_RCC_GPIOB_CLK_ENABLE(); 63 | } 64 | else if(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i] == GPIOC) 65 | { 66 | __HAL_RCC_GPIOC_CLK_ENABLE(); 67 | } 68 | else if(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i] == GPIOD) 69 | { 70 | __HAL_RCC_GPIOD_CLK_ENABLE(); 71 | } 72 | else if(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i] == GPIOE) 73 | { 74 | __HAL_RCC_GPIOE_CLK_ENABLE(); 75 | } 76 | GPIO_InitStruct.Pin = SEVEN_SEG_CfgParam[au16_Instance].SEG_PIN[i]; 77 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 78 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; 79 | HAL_GPIO_Init(SEVEN_SEG_CfgParam[au16_Instance].SEG_GPIO[i], &GPIO_InitStruct); 80 | } 81 | /*--------[ Configure The 7-Segments Enable Signals GPIO Pins ]-------*/ 82 | for(i=0; iInstance = STEPPER_TIMER; 125 | TMR_Handle->Init.Prescaler = 99; 126 | TMR_Handle->Init.CounterMode = TIM_COUNTERMODE_UP; 127 | TMR_Handle->Init.Period = ARR_Value-1; 128 | TMR_Handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 129 | TMR_Handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; 130 | HAL_TIM_Base_Init(TMR_Handle); 131 | sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 132 | HAL_TIM_ConfigClockSource(TMR_Handle, &sClockSourceConfig); 133 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 134 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 135 | HAL_TIMEx_MasterConfigSynchronization(TMR_Handle, &sMasterConfig); 136 | HAL_TIM_Base_Start_IT(TMR_Handle); 137 | } 138 | } 139 | 140 | void STEPPER_SetSpeed(uint8_t au8_STEPPER_Instance, uint16_t au16_RPM) 141 | { 142 | uint32_t Total_Steps = 0; 143 | 144 | gs_STEPPER_info[au8_STEPPER_Instance].RPM = au16_RPM; 145 | if(STEPPER_CfgParam[au8_STEPPER_Instance].STEPPING_Mode == HALF_STEP_DRIVE) 146 | { 147 | Total_Steps = STEPPER_CfgParam[au8_STEPPER_Instance].STEPS_PER_REV << 1; 148 | } 149 | else 150 | { 151 | Total_Steps = STEPPER_CfgParam[au8_STEPPER_Instance].STEPS_PER_REV; 152 | } 153 | gs_STEPPER_info[au8_STEPPER_Instance].Max_Ticks = (60000.0)/(STEPPER_TIME_BASE * Total_Steps * au16_RPM); 154 | } 155 | 156 | static void STEPPER_One_Step(uint8_t i) 157 | { 158 | // For UniPolar Stepper Motors 159 | if(STEPPER_CfgParam[i].STEPPER_Cfg == STEPPER_UNIPOLAR) 160 | { 161 | if(STEPPER_CfgParam[i].STEPPING_Mode == WAVE_DRIVE) 162 | { 163 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[0], STEPPER_CfgParam[i].IN_PIN[0], UNIPOLAR_WD_PATTERN[gs_STEPPER_info[i].Step_Index][0]); 164 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[1], STEPPER_CfgParam[i].IN_PIN[1], UNIPOLAR_WD_PATTERN[gs_STEPPER_info[i].Step_Index][1]); 165 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[2], STEPPER_CfgParam[i].IN_PIN[2], UNIPOLAR_WD_PATTERN[gs_STEPPER_info[i].Step_Index][2]); 166 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[3], STEPPER_CfgParam[i].IN_PIN[3], UNIPOLAR_WD_PATTERN[gs_STEPPER_info[i].Step_Index][3]); 167 | } 168 | else if(STEPPER_CfgParam[i].STEPPING_Mode == FULL_STEP_DRIVE) 169 | { 170 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[0], STEPPER_CfgParam[i].IN_PIN[0], UNIPOLAR_FS_PATTERN[gs_STEPPER_info[i].Step_Index][0]); 171 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[1], STEPPER_CfgParam[i].IN_PIN[1], UNIPOLAR_FS_PATTERN[gs_STEPPER_info[i].Step_Index][1]); 172 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[2], STEPPER_CfgParam[i].IN_PIN[2], UNIPOLAR_FS_PATTERN[gs_STEPPER_info[i].Step_Index][2]); 173 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[3], STEPPER_CfgParam[i].IN_PIN[3], UNIPOLAR_FS_PATTERN[gs_STEPPER_info[i].Step_Index][3]); 174 | } 175 | else if(STEPPER_CfgParam[i].STEPPING_Mode == HALF_STEP_DRIVE) 176 | { 177 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[0], STEPPER_CfgParam[i].IN_PIN[0], UNIPOLAR_HS_PATTERN[gs_STEPPER_info[i].Step_Index][0]); 178 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[1], STEPPER_CfgParam[i].IN_PIN[1], UNIPOLAR_HS_PATTERN[gs_STEPPER_info[i].Step_Index][1]); 179 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[2], STEPPER_CfgParam[i].IN_PIN[2], UNIPOLAR_HS_PATTERN[gs_STEPPER_info[i].Step_Index][2]); 180 | HAL_GPIO_WritePin(STEPPER_CfgParam[i].IN_GPIO[3], STEPPER_CfgParam[i].IN_PIN[3], UNIPOLAR_HS_PATTERN[gs_STEPPER_info[i].Step_Index][3]); 181 | } 182 | } 183 | // For BiPolar Stepper Motors 184 | else if(STEPPER_CfgParam[i].STEPPER_Cfg == STEPPER_BIPOLAR) 185 | { 186 | 187 | } 188 | // Update & Check The Index 189 | if(gs_STEPPER_info[i].Dir == DIR_CCW) 190 | { 191 | if(gs_STEPPER_info[i].Step_Index == 0) 192 | { 193 | gs_STEPPER_info[i].Step_Index = gs_STEPPER_info[i].Max_Index; 194 | } 195 | gs_STEPPER_info[i].Step_Index--; 196 | } 197 | else if(gs_STEPPER_info[i].Dir == DIR_CW) 198 | { 199 | gs_STEPPER_info[i].Step_Index++; 200 | if(gs_STEPPER_info[i].Step_Index == gs_STEPPER_info[i].Max_Index) 201 | { 202 | gs_STEPPER_info[i].Step_Index = 0; 203 | } 204 | } 205 | } 206 | 207 | void STEPPER_Step_Blocking(uint8_t au8_STEPPER_Instance, uint32_t au32_Steps, uint8_t au8_DIR) 208 | { 209 | uint32_t i = 0; 210 | uint32_t DelayTimeMs = 0; 211 | 212 | gs_STEPPER_info[au8_STEPPER_Instance].Blocked = 1; 213 | DelayTimeMs = (60000/(gs_STEPPER_info[au8_STEPPER_Instance].RPM * STEPPER_CfgParam[au8_STEPPER_Instance].STEPS_PER_REV)); 214 | // Send The Control Signals 215 | for(i=0; i= gs_STEPPER_info[i].Max_Ticks) && (gs_STEPPER_info[i].Blocked != 1) && (gs_STEPPER_info[i].Steps > 0)) 241 | { 242 | STEPPER_One_Step(i); 243 | gs_STEPPER_info[i].Steps--; 244 | gs_STEPPER_info[i].Ticks = 0; 245 | } 246 | else 247 | { 248 | gs_STEPPER_info[i].Ticks++; 249 | } 250 | } 251 | } 252 | 253 | void STEPPER_TMR_OVF_ISR(TIM_HandleTypeDef* htim) 254 | { 255 | uint8_t i = 0; 256 | 257 | if(htim->Instance == STEPPER_TIMER) 258 | { 259 | for(i=0; i= gs_STEPPER_info[i].Max_Ticks) && (gs_STEPPER_info[i].Blocked != 1) && (gs_STEPPER_info[i].Steps > 0)) 262 | { 263 | STEPPER_One_Step(i); 264 | gs_STEPPER_info[i].Steps--; 265 | gs_STEPPER_info[i].Ticks = 0; 266 | } 267 | else 268 | { 269 | gs_STEPPER_info[i].Ticks++; 270 | } 271 | } 272 | } 273 | } 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /ECUAL/STEPPER/STEPPER.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: STEPPER.h 3 | * Driver Name: [[ STEPPER Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.0 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef STEPPER_H_ 15 | #define STEPPER_H_ 16 | 17 | // Replace The "#include" File Below With The CPU Relevant One For Your Board 18 | #include "stm32l4xx.h" 19 | 20 | // The Number OF Stepper Motors To Be Used In The Project 21 | #define STEPPER_UNITS 1 22 | 23 | // Stepper Timer Base Options 24 | #define STEPPER_TIMER_EN 1 25 | #define STEPPER_TIMER TIM15 26 | #define STEPPER_TIMER_CLK 80 27 | #define STEPPER_TIME_BASE 1 28 | 29 | // Stepper Motor Configurations & Mode 30 | #define WAVE_DRIVE 0 31 | #define FULL_STEP_DRIVE 1 32 | #define HALF_STEP_DRIVE 2 33 | #define STEPPER_UNIPOLAR 0 34 | #define STEPPER_BIPOLAR 1 35 | #define DIR_CW 0 36 | #define DIR_CCW 1 37 | 38 | // Stepper Configuration Parameter Structure 39 | typedef struct 40 | { 41 | GPIO_TypeDef * IN_GPIO[4]; 42 | uint16_t IN_PIN[4]; 43 | uint16_t STEPS_PER_REV; 44 | uint8_t STEPPER_Cfg; 45 | uint8_t STEPPING_Mode; 46 | }STEPPER_CfgType; 47 | 48 | /*-----[ Prototypes For All Functions ]-----*/ 49 | 50 | void STEPPERS_Init(void); 51 | void STEPPERS_Init_TMR(TIM_HandleTypeDef* TMR_Handle); 52 | void STEPPER_SetSpeed(uint8_t au8_STEPPER_Instance, uint16_t au16_RPM); 53 | void STEPPER_Step_Blocking(uint8_t au8_STEPPER_Instance, uint32_t au32_Steps, uint8_t au8_DIR); 54 | void STEPPER_Step_NonBlocking(uint8_t au8_STEPPER_Instance, uint32_t au32_Steps, uint8_t au8_DIR); 55 | void STEPPER_Stop(uint8_t au8_STEPPER_Instance); 56 | void STEPPER_Main(void); 57 | void STEPPER_TMR_OVF_ISR(TIM_HandleTypeDef* htim); 58 | 59 | #endif /* STEPPER_H_ */ 60 | -------------------------------------------------------------------------------- /ECUAL/STEPPER/STEPPER_cfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: STEPPER_cfg.c 3 | * Driver Name: [[ STEPPER Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "STEPPER.h" 14 | 15 | const STEPPER_CfgType STEPPER_CfgParam[STEPPER_UNITS] = 16 | { 17 | // Stepper Motor 1 Configurations 18 | { 19 | {GPIOA, GPIOA, GPIOB, GPIOB}, 20 | {GPIO_PIN_8, GPIO_PIN_11, GPIO_PIN_5, GPIO_PIN_4}, 21 | 2038, 22 | STEPPER_UNIPOLAR, 23 | FULL_STEP_DRIVE 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /ECUAL/STEPPER/STEPPER_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: STEPPER_cfg.h 3 | * Driver Name: [[ STEPPER Motor ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef STEPPER_CFG_H_ 14 | #define STEPPER_CFG_H_ 15 | 16 | #include "STEPPER.h" 17 | 18 | extern const STEPPER_CfgType STEPPER_CfgParam[STEPPER_UNITS]; 19 | 20 | #endif /* STEPPER_CFG_H_ */ 21 | -------------------------------------------------------------------------------- /MATH/FIR/FIR.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FIR.c 3 | * Driver Name: [[ FIR Digital Filters ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "FIR.h" 14 | 15 | 16 | void AVG_FIR_LPF(FILTER_DATA_TYPE IN, FILTER_DATA_TYPE* OUT, FIR_Filter_cfg* FILTER_OBJ) 17 | { 18 | FILTER_DATA_TYPE SUM = 0; 19 | uint16_t i = 0; 20 | 21 | // Push The New Input To The History Buffer 22 | FILTER_OBJ->Data_Buffer[FILTER_OBJ->Buffer_Index] = IN; 23 | FILTER_OBJ->Buffer_Index++; 24 | if(FILTER_OBJ->Buffer_Index == FILTER_OBJ->Filter_Order+1) 25 | { 26 | FILTER_OBJ->Buffer_Index = 0; 27 | } 28 | 29 | // Calculate The Average For The Data In The Buffer 30 | for(i=0; i < FILTER_OBJ->Filter_Order+1; i++) 31 | { 32 | SUM += FILTER_OBJ->Data_Buffer[i]; 33 | } 34 | 35 | *OUT = SUM / (FILTER_OBJ->Filter_Order+1); 36 | } 37 | 38 | void SUM_BUFFER(FILTER_DATA_TYPE IN, FILTER_DATA_TYPE* SUM, FIR_Filter_cfg* FILTER_OBJ) 39 | { 40 | int32_t temp_sum = 0; 41 | uint16_t i = 0; 42 | 43 | // Push The New Input To The History Buffer 44 | FILTER_OBJ->Data_Buffer[FILTER_OBJ->Buffer_Index] = IN; 45 | FILTER_OBJ->Buffer_Index++; 46 | 47 | if(FILTER_OBJ->Buffer_Index == FILTER_OBJ->Filter_Order+1) 48 | { FILTER_OBJ->Buffer_Index = 0; } 49 | 50 | // Calculate The Accumulated Sum For The Buffer Data 51 | for(i = 0; i < FILTER_OBJ->Filter_Order+1; i++) 52 | { 53 | temp_sum += FILTER_OBJ->Data_Buffer[i]; 54 | } 55 | *SUM = (FILTER_DATA_TYPE)temp_sum; 56 | } 57 | -------------------------------------------------------------------------------- /MATH/FIR/FIR.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FIR.h 3 | * Driver Name: [[ FIR Digital Filters ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Ver: 1.1 7 | * Author: Khaled Magdy 8 | * ------------------------------------------- 9 | * For More Information, Tutorials, etc. 10 | * Visit Website: www.DeepBlueMbedded.com 11 | * 12 | */ 13 | 14 | #ifndef FIR_H 15 | #define FIR_H 16 | 17 | #include 18 | 19 | #define FILTER_DATA_TYPE float 20 | 21 | 22 | typedef struct 23 | { 24 | uint16_t Filter_Order; 25 | uint16_t Buffer_Index; 26 | FILTER_DATA_TYPE* Data_Buffer; 27 | float* Filter_Coeffecients; 28 | }FIR_Filter_cfg; 29 | 30 | 31 | void AVG_FIR_LPF(FILTER_DATA_TYPE IN, FILTER_DATA_TYPE* OUT, FIR_Filter_cfg* FILTER_OBJ); 32 | 33 | void SUM_BUFFER(FILTER_DATA_TYPE IN, FILTER_DATA_TYPE* SUM, FIR_Filter_cfg* FILTER_OBJ); 34 | 35 | 36 | #endif /* FIR_H */ 37 | 38 | -------------------------------------------------------------------------------- /MATH/MATH.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: MATH.c 3 | * Driver Name: [[ MATH Functions ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #include "MATH.h" 14 | 15 | uint32_t MAP(uint32_t au32_IN, uint32_t au32_INmin, uint32_t au32_INmax, uint32_t au32_OUTmin, uint32_t au32_OUTmax) 16 | { 17 | return ((((au32_IN - au32_INmin)*(au32_OUTmax - au32_OUTmin))/(au32_INmax - au32_INmin)) + au32_OUTmin); 18 | } 19 | 20 | uint32_t Constrain(uint32_t au32_IN, uint32_t au32_MIN, uint32_t au32_MAX) 21 | { 22 | if(au32_IN < au32_MIN) 23 | { 24 | return au32_MIN; 25 | } 26 | else if (au32_IN > au32_MAX) 27 | { 28 | return au32_MAX; 29 | } 30 | else 31 | { 32 | return au32_IN; 33 | } 34 | } 35 | 36 | MATH_DataType MIN(MATH_DataType* IN_Arr, uint32_t au32_LEN) 37 | { 38 | uint32_t i = 0; 39 | MATH_DataType MIN = 0; 40 | 41 | for(i=0; i MAX) 59 | { 60 | MAX = IN_Arr[i]; 61 | } 62 | } 63 | return MAX; 64 | } 65 | -------------------------------------------------------------------------------- /MATH/MATH.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: MATH.h 3 | * Driver Name: [[ MATH Functions ]] 4 | * SW Layer: ECUAL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | * 11 | */ 12 | 13 | #ifndef MATH_H_ 14 | #define MATH_H_ 15 | 16 | #include 17 | 18 | typedef uint32_t MATH_DataType; 19 | 20 | uint32_t MAP(uint32_t au32_IN, uint32_t au32_INmin, uint32_t au32_INmax, uint32_t au32_OUTmin, uint32_t au32_OUTmax); 21 | 22 | uint32_t Constrain(uint32_t au32_IN, uint32_t au32_MIN, uint32_t au32_MAX); 23 | 24 | MATH_DataType MIN(MATH_DataType* IN_Arr, uint32_t au32_LEN); 25 | 26 | MATH_DataType MAX(MATH_DataType* IN_Arr, uint32_t au32_LEN); 27 | 28 | #endif /* MATH_H_ */ 29 | -------------------------------------------------------------------------------- /MIDWARE/FATFS_SD/FATFS_SD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FATFS_SD.c 3 | * Driver Name: [[ FATFS_SD SPI ]] 4 | * SW Layer: MIDWARE 5 | * Author: Khaled Magdy 6 | * ------------------------------------------- 7 | * For More Information, Tutorials, etc. 8 | * Visit Website: www.DeepBlueMbedded.com 9 | */ 10 | #include "main.h" 11 | #include "diskio.h" 12 | #include "FATFS_SD.h" 13 | 14 | #define TRUE 1 15 | #define FALSE 0 16 | #define bool BYTE 17 | 18 | static volatile DSTATUS Stat = STA_NOINIT; /* Disk Status */ 19 | uint16_t Timer1, Timer2; /* 1ms Timer Counters */ 20 | static uint8_t CardType; /* Type 0:MMC, 1:SDC, 2:Block addressing */ 21 | static uint8_t PowerFlag = 0; /* Power flag */ 22 | 23 | //-----[ SPI Functions ]----- 24 | 25 | /* slave select */ 26 | static void SELECT(void) 27 | { 28 | HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_RESET); 29 | } 30 | 31 | /* slave deselect */ 32 | static void DESELECT(void) 33 | { 34 | HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_SET); 35 | } 36 | 37 | /* SPI transmit a byte */ 38 | static void SPI_TxByte(uint8_t data) 39 | { 40 | while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE)); 41 | HAL_SPI_Transmit(HSPI_SDCARD, &data, 1, SPI_TIMEOUT); 42 | } 43 | 44 | /* SPI transmit buffer */ 45 | static void SPI_TxBuffer(uint8_t *buffer, uint16_t len) 46 | { 47 | while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE)); 48 | HAL_SPI_Transmit(HSPI_SDCARD, buffer, len, SPI_TIMEOUT); 49 | } 50 | 51 | /* SPI receive a byte */ 52 | static uint8_t SPI_RxByte(void) 53 | { 54 | uint8_t dummy, data; 55 | dummy = 0xFF; 56 | while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE)); 57 | HAL_SPI_TransmitReceive(HSPI_SDCARD, &dummy, &data, 1, SPI_TIMEOUT); 58 | return data; 59 | } 60 | 61 | /* SPI receive a byte via pointer */ 62 | static void SPI_RxBytePtr(uint8_t *buff) 63 | { 64 | *buff = SPI_RxByte(); 65 | } 66 | 67 | //-----[ SD Card Functions ]----- 68 | 69 | /* wait SD ready */ 70 | static uint8_t SD_ReadyWait(void) 71 | { 72 | uint8_t res; 73 | /* timeout 500ms */ 74 | Timer2 = 500; 75 | /* if SD goes ready, receives 0xFF */ 76 | do { 77 | res = SPI_RxByte(); 78 | } while ((res != 0xFF) && Timer2); 79 | return res; 80 | } 81 | 82 | /* power on */ 83 | static void SD_PowerOn(void) 84 | { 85 | uint8_t args[6]; 86 | uint32_t cnt = 0x1FFF; 87 | /* transmit bytes to wake up */ 88 | DESELECT(); 89 | for(int i = 0; i < 10; i++) 90 | { 91 | SPI_TxByte(0xFF); 92 | } 93 | /* slave select */ 94 | SELECT(); 95 | /* make idle state */ 96 | args[0] = CMD0; /* CMD0:GO_IDLE_STATE */ 97 | args[1] = 0; 98 | args[2] = 0; 99 | args[3] = 0; 100 | args[4] = 0; 101 | args[5] = 0x95; 102 | SPI_TxBuffer(args, sizeof(args)); 103 | /* wait response */ 104 | while ((SPI_RxByte() != 0x01) && cnt) 105 | { 106 | cnt--; 107 | } 108 | DESELECT(); 109 | SPI_TxByte(0XFF); 110 | PowerFlag = 1; 111 | } 112 | 113 | /* power off */ 114 | static void SD_PowerOff(void) 115 | { 116 | PowerFlag = 0; 117 | } 118 | 119 | /* check power flag */ 120 | static uint8_t SD_CheckPower(void) 121 | { 122 | return PowerFlag; 123 | } 124 | 125 | /* receive data block */ 126 | static bool SD_RxDataBlock(BYTE *buff, UINT len) 127 | { 128 | uint8_t token; 129 | /* timeout 200ms */ 130 | Timer1 = 200; 131 | /* loop until receive a response or timeout */ 132 | do { 133 | token = SPI_RxByte(); 134 | } while((token == 0xFF) && Timer1); 135 | /* invalid response */ 136 | if(token != 0xFE) return FALSE; 137 | /* receive data */ 138 | do { 139 | SPI_RxBytePtr(buff++); 140 | } while(len--); 141 | /* discard CRC */ 142 | SPI_RxByte(); 143 | SPI_RxByte(); 144 | return TRUE; 145 | } 146 | 147 | /* transmit data block */ 148 | #if _USE_WRITE == 1 149 | static bool SD_TxDataBlock(const uint8_t *buff, BYTE token) 150 | { 151 | uint8_t resp; 152 | uint8_t i = 0; 153 | /* wait SD ready */ 154 | if (SD_ReadyWait() != 0xFF) return FALSE; 155 | /* transmit token */ 156 | SPI_TxByte(token); 157 | /* if it's not STOP token, transmit data */ 158 | if (token != 0xFD) 159 | { 160 | SPI_TxBuffer((uint8_t*)buff, 512); 161 | /* discard CRC */ 162 | SPI_RxByte(); 163 | SPI_RxByte(); 164 | /* receive response */ 165 | while (i <= 64) 166 | { 167 | resp = SPI_RxByte(); 168 | /* transmit 0x05 accepted */ 169 | if ((resp & 0x1F) == 0x05) break; 170 | i++; 171 | } 172 | /* recv buffer clear */ 173 | while (SPI_RxByte() == 0); 174 | } 175 | /* transmit 0x05 accepted */ 176 | if ((resp & 0x1F) == 0x05) return TRUE; 177 | 178 | return FALSE; 179 | } 180 | #endif /* _USE_WRITE */ 181 | 182 | /* transmit command */ 183 | static BYTE SD_SendCmd(BYTE cmd, uint32_t arg) 184 | { 185 | uint8_t crc, res; 186 | /* wait SD ready */ 187 | if (SD_ReadyWait() != 0xFF) return 0xFF; 188 | /* transmit command */ 189 | SPI_TxByte(cmd); /* Command */ 190 | SPI_TxByte((uint8_t)(arg >> 24)); /* Argument[31..24] */ 191 | SPI_TxByte((uint8_t)(arg >> 16)); /* Argument[23..16] */ 192 | SPI_TxByte((uint8_t)(arg >> 8)); /* Argument[15..8] */ 193 | SPI_TxByte((uint8_t)arg); /* Argument[7..0] */ 194 | /* prepare CRC */ 195 | if(cmd == CMD0) crc = 0x95; /* CRC for CMD0(0) */ 196 | else if(cmd == CMD8) crc = 0x87; /* CRC for CMD8(0x1AA) */ 197 | else crc = 1; 198 | /* transmit CRC */ 199 | SPI_TxByte(crc); 200 | /* Skip a stuff byte when STOP_TRANSMISSION */ 201 | if (cmd == CMD12) SPI_RxByte(); 202 | /* receive response */ 203 | uint8_t n = 10; 204 | do { 205 | res = SPI_RxByte(); 206 | } while ((res & 0x80) && --n); 207 | 208 | return res; 209 | } 210 | 211 | //-----[ user_diskio.c Functions ]----- 212 | 213 | /* initialize SD */ 214 | DSTATUS SD_disk_initialize(BYTE drv) 215 | { 216 | uint8_t n, type, ocr[4]; 217 | /* single drive, drv should be 0 */ 218 | if(drv) return STA_NOINIT; 219 | /* no disk */ 220 | if(Stat & STA_NODISK) return Stat; 221 | /* power on */ 222 | SD_PowerOn(); 223 | /* slave select */ 224 | SELECT(); 225 | /* check disk type */ 226 | type = 0; 227 | /* send GO_IDLE_STATE command */ 228 | if (SD_SendCmd(CMD0, 0) == 1) 229 | { 230 | /* timeout 1 sec */ 231 | Timer1 = 1000; 232 | /* SDC V2+ accept CMD8 command, http://elm-chan.org/docs/mmc/mmc_e.html */ 233 | if (SD_SendCmd(CMD8, 0x1AA) == 1) 234 | { 235 | /* operation condition register */ 236 | for (n = 0; n < 4; n++) 237 | { 238 | ocr[n] = SPI_RxByte(); 239 | } 240 | /* voltage range 2.7-3.6V */ 241 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) 242 | { 243 | /* ACMD41 with HCS bit */ 244 | do { 245 | if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 1UL << 30) == 0) break; 246 | } while (Timer1); 247 | 248 | /* READ_OCR */ 249 | if (Timer1 && SD_SendCmd(CMD58, 0) == 0) 250 | { 251 | /* Check CCS bit */ 252 | for (n = 0; n < 4; n++) 253 | { 254 | ocr[n] = SPI_RxByte(); 255 | } 256 | 257 | /* SDv2 (HC or SC) */ 258 | type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; 259 | } 260 | } 261 | } 262 | else 263 | { 264 | /* SDC V1 or MMC */ 265 | type = (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) <= 1) ? CT_SD1 : CT_MMC; 266 | do 267 | { 268 | if (type == CT_SD1) 269 | { 270 | if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) == 0) break; /* ACMD41 */ 271 | } 272 | else 273 | { 274 | if (SD_SendCmd(CMD1, 0) == 0) break; /* CMD1 */ 275 | } 276 | } while (Timer1); 277 | /* SET_BLOCKLEN */ 278 | if (!Timer1 || SD_SendCmd(CMD16, 512) != 0) type = 0; 279 | } 280 | } 281 | CardType = type; 282 | /* Idle */ 283 | DESELECT(); 284 | SPI_RxByte(); 285 | /* Clear STA_NOINIT */ 286 | if (type) 287 | { 288 | Stat &= ~STA_NOINIT; 289 | } 290 | else 291 | { 292 | /* Initialization failed */ 293 | SD_PowerOff(); 294 | } 295 | return Stat; 296 | } 297 | 298 | /* return disk status */ 299 | DSTATUS SD_disk_status(BYTE drv) 300 | { 301 | if (drv) return STA_NOINIT; 302 | return Stat; 303 | } 304 | 305 | /* read sector */ 306 | DRESULT SD_disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) 307 | { 308 | /* pdrv should be 0 */ 309 | if (pdrv || !count) return RES_PARERR; 310 | 311 | /* no disk */ 312 | if (Stat & STA_NOINIT) return RES_NOTRDY; 313 | 314 | /* convert to byte address */ 315 | if (!(CardType & CT_SD2)) sector *= 512; 316 | 317 | SELECT(); 318 | 319 | if (count == 1) 320 | { 321 | /* READ_SINGLE_BLOCK */ 322 | if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, 512)) count = 0; 323 | } 324 | else 325 | { 326 | /* READ_MULTIPLE_BLOCK */ 327 | if (SD_SendCmd(CMD18, sector) == 0) 328 | { 329 | do { 330 | if (!SD_RxDataBlock(buff, 512)) break; 331 | buff += 512; 332 | } while (--count); 333 | 334 | /* STOP_TRANSMISSION */ 335 | SD_SendCmd(CMD12, 0); 336 | } 337 | } 338 | 339 | /* Idle */ 340 | DESELECT(); 341 | SPI_RxByte(); 342 | 343 | return count ? RES_ERROR : RES_OK; 344 | } 345 | 346 | /* write sector */ 347 | #if _USE_WRITE == 1 348 | DRESULT SD_disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) 349 | { 350 | /* pdrv should be 0 */ 351 | if (pdrv || !count) return RES_PARERR; 352 | 353 | /* no disk */ 354 | if (Stat & STA_NOINIT) return RES_NOTRDY; 355 | 356 | /* write protection */ 357 | if (Stat & STA_PROTECT) return RES_WRPRT; 358 | 359 | /* convert to byte address */ 360 | if (!(CardType & CT_SD2)) sector *= 512; 361 | 362 | SELECT(); 363 | 364 | if (count == 1) 365 | { 366 | /* WRITE_BLOCK */ 367 | if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, 0xFE)) 368 | count = 0; 369 | } 370 | else 371 | { 372 | /* WRITE_MULTIPLE_BLOCK */ 373 | if (CardType & CT_SD1) 374 | { 375 | SD_SendCmd(CMD55, 0); 376 | SD_SendCmd(CMD23, count); /* ACMD23 */ 377 | } 378 | 379 | if (SD_SendCmd(CMD25, sector) == 0) 380 | { 381 | do { 382 | if(!SD_TxDataBlock(buff, 0xFC)) break; 383 | buff += 512; 384 | } while (--count); 385 | 386 | /* STOP_TRAN token */ 387 | if(!SD_TxDataBlock(0, 0xFD)) 388 | { 389 | count = 1; 390 | } 391 | } 392 | } 393 | 394 | /* Idle */ 395 | DESELECT(); 396 | SPI_RxByte(); 397 | 398 | return count ? RES_ERROR : RES_OK; 399 | } 400 | #endif /* _USE_WRITE */ 401 | 402 | /* ioctl */ 403 | DRESULT SD_disk_ioctl(BYTE drv, BYTE ctrl, void *buff) 404 | { 405 | DRESULT res; 406 | uint8_t n, csd[16], *ptr = buff; 407 | WORD csize; 408 | 409 | /* pdrv should be 0 */ 410 | if (drv) return RES_PARERR; 411 | res = RES_ERROR; 412 | 413 | if (ctrl == CTRL_POWER) 414 | { 415 | switch (*ptr) 416 | { 417 | case 0: 418 | SD_PowerOff(); /* Power Off */ 419 | res = RES_OK; 420 | break; 421 | case 1: 422 | SD_PowerOn(); /* Power On */ 423 | res = RES_OK; 424 | break; 425 | case 2: 426 | *(ptr + 1) = SD_CheckPower(); 427 | res = RES_OK; /* Power Check */ 428 | break; 429 | default: 430 | res = RES_PARERR; 431 | } 432 | } 433 | else 434 | { 435 | /* no disk */ 436 | if (Stat & STA_NOINIT){ 437 | return RES_NOTRDY; 438 | } 439 | SELECT(); 440 | switch (ctrl) 441 | { 442 | case GET_SECTOR_COUNT: 443 | /* SEND_CSD */ 444 | if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(csd, 16)) 445 | { 446 | if ((csd[0] >> 6) == 1) 447 | { 448 | /* SDC V2 */ 449 | csize = csd[9] + ((WORD) csd[8] << 8) + 1; 450 | *(DWORD*) buff = (DWORD) csize << 10; 451 | } 452 | else 453 | { 454 | /* MMC or SDC V1 */ 455 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; 456 | csize = (csd[8] >> 6) + ((WORD) csd[7] << 2) + ((WORD) (csd[6] & 3) << 10) + 1; 457 | *(DWORD*) buff = (DWORD) csize << (n - 9); 458 | } 459 | res = RES_OK; 460 | } 461 | break; 462 | case GET_SECTOR_SIZE: 463 | *(WORD*) buff = 512; 464 | res = RES_OK; 465 | break; 466 | case CTRL_SYNC: 467 | if (SD_ReadyWait() == 0xFF) res = RES_OK; 468 | break; 469 | case MMC_GET_CSD: 470 | /* SEND_CSD */ 471 | if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(ptr, 16)) res = RES_OK; 472 | break; 473 | case MMC_GET_CID: 474 | /* SEND_CID */ 475 | if (SD_SendCmd(CMD10, 0) == 0 && SD_RxDataBlock(ptr, 16)) res = RES_OK; 476 | break; 477 | case MMC_GET_OCR: 478 | /* READ_OCR */ 479 | if (SD_SendCmd(CMD58, 0) == 0) 480 | { 481 | for (n = 0; n < 4; n++) 482 | { 483 | *ptr++ = SPI_RxByte(); 484 | } 485 | res = RES_OK; 486 | } 487 | default: 488 | res = RES_PARERR; 489 | } 490 | DESELECT(); 491 | SPI_RxByte(); 492 | } 493 | return res; 494 | } 495 | -------------------------------------------------------------------------------- /MIDWARE/FATFS_SD/FATFS_SD.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FATFS_SD.h 3 | * Driver Name: [[ FATFS_SD SPI ]] 4 | * SW Layer: MIDWARE 5 | * Author: Khaled Magdy 6 | * ------------------------------------------- 7 | * For More Information, Tutorials, etc. 8 | * Visit Website: www.DeepBlueMbedded.com 9 | */ 10 | #ifndef FATFS_SD_H_ 11 | #define FATFS_SD_H_ 12 | 13 | //-----[ SD Card SPI Interface Cfgs ]----- 14 | 15 | extern SPI_HandleTypeDef hspi2; 16 | #define HSPI_SDCARD &hspi2 17 | #define SD_CS_PORT GPIOB 18 | #define SD_CS_PIN GPIO_PIN_12 19 | #define SPI_TIMEOUT 100 20 | 21 | //-----[ MMC/SDC Commands ]----- 22 | #define CMD0 (0x40+0) /* GO_IDLE_STATE */ 23 | #define CMD1 (0x40+1) /* SEND_OP_COND */ 24 | #define CMD8 (0x40+8) /* SEND_IF_COND */ 25 | #define CMD9 (0x40+9) /* SEND_CSD */ 26 | #define CMD10 (0x40+10) /* SEND_CID */ 27 | #define CMD12 (0x40+12) /* STOP_TRANSMISSION */ 28 | #define CMD16 (0x40+16) /* SET_BLOCKLEN */ 29 | #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ 30 | #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ 31 | #define CMD23 (0x40+23) /* SET_BLOCK_COUNT */ 32 | #define CMD24 (0x40+24) /* WRITE_BLOCK */ 33 | #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ 34 | #define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */ 35 | #define CMD55 (0x40+55) /* APP_CMD */ 36 | #define CMD58 (0x40+58) /* READ_OCR */ 37 | 38 | //-----[ MMC Card Types (MMC_GET_TYPE) ]----- 39 | #define CT_MMC 0x01 /* MMC ver 3 */ 40 | #define CT_SD1 0x02 /* SD ver 1 */ 41 | #define CT_SD2 0x04 /* SD ver 2 */ 42 | #define CT_SDC 0x06 /* SD */ 43 | #define CT_BLOCK 0x08 /* Block addressing */ 44 | 45 | //-----[ Prototypes For All User External Functions ]----- 46 | DSTATUS SD_disk_initialize(BYTE pdrv); 47 | DSTATUS SD_disk_status(BYTE pdrv); 48 | DRESULT SD_disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 49 | DRESULT SD_disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 50 | DRESULT SD_disk_ioctl(BYTE pdrv, BYTE cmd, void* buff); 51 | 52 | #endif /* FATFS_SD_H_ */ 53 | -------------------------------------------------------------------------------- /MIDWARE/FEE/FEE.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FEE.c 3 | * Driver Name: [[ FEE (Flash EEPROM Emulation) ]] 4 | * SW Layer: MIDWARE 5 | * Author: Khaled Magdy 6 | * ------------------------------------------- 7 | * For More Information, Tutorials, etc. 8 | * Visit Website: www.DeepBlueMbedded.com 9 | */ 10 | #include "FEE.h" 11 | #include "string.h" 12 | 13 | HAL_StatusTypeDef FEE_Write(uint32_t address, uint16_t *data, uint32_t dataSize) 14 | { 15 | HAL_StatusTypeDef status = HAL_OK; 16 | uint32_t pageAddress = address & ~(FLASH_PAGE_SIZE - 1); // Get the start address of the page 17 | uint16_t buffer[FEE_BUFFER_LEN]; // Create a buffer to hold the entire page 18 | HAL_FLASH_Unlock(); 19 | // Read the entire page into the buffer 20 | for (uint32_t i = 0; i < FEE_BUFFER_LEN; i++) { 21 | buffer[i] = *(__IO uint16_t*)(pageAddress + i * 2); 22 | } 23 | // Modify the values at the desired address 24 | uint32_t offset = address - pageAddress; 25 | for (uint32_t i = 0; i < dataSize; i++) { 26 | buffer[offset / 2 + i] = data[i]; 27 | } 28 | // Erase the page 29 | FLASH_EraseInitTypeDef eraseInitStruct; 30 | eraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; 31 | eraseInitStruct.PageAddress = pageAddress; 32 | eraseInitStruct.NbPages = 1; 33 | uint32_t pageError; 34 | status = HAL_FLASHEx_Erase(&eraseInitStruct, &pageError); 35 | if (status != HAL_OK) { 36 | HAL_FLASH_Lock(); 37 | return status; 38 | } 39 | // Write the modified buffer back to the page 40 | for (uint32_t i = 0; i < FEE_BUFFER_LEN; i++) { 41 | status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, pageAddress + i * 2, buffer[i]); 42 | if (status != HAL_OK) { 43 | break; 44 | } 45 | } 46 | HAL_FLASH_Lock(); 47 | return status; 48 | } 49 | 50 | void FEE_Read(uint32_t address, uint16_t *data, uint32_t dataSize) 51 | { 52 | for (uint32_t i = 0; i < dataSize; i++) { 53 | data[i] = *(__IO uint16_t*)address; 54 | address += 2; 55 | } 56 | } 57 | 58 | // Generic APIs For Any Data Type 59 | void FEE_WriteData(uint32_t address, void *data, size_t dataSize) 60 | { 61 | uint16_t bytes[dataSize / 2]; 62 | memcpy(bytes, data, dataSize); 63 | FEE_Write(address, bytes, dataSize); 64 | } 65 | 66 | void FEE_ReadData(uint32_t address, void *data, size_t dataSize) 67 | { 68 | uint16_t bytes[dataSize / 2]; 69 | FEE_Read(address, bytes, dataSize); 70 | memcpy(data, bytes, dataSize); 71 | } 72 | 73 | -------------------------------------------------------------------------------- /MIDWARE/FEE/FEE.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FEE.h 3 | * Driver Name: [[ FEE (Flash EEPROM Emulation) ]] 4 | * SW Layer: MIDWARE 5 | * Author: Khaled Magdy 6 | * ------------------------------------------- 7 | * For More Information, Tutorials, etc. 8 | * Visit Website: www.DeepBlueMbedded.com 9 | */ 10 | #ifndef FEE_H_ 11 | #define FEE_H_ 12 | /* 13 | * Disclaimer: This library is a quick & dirty implementation for FLASH wrapper functions 14 | * That may be helpful for basic applications, not for use in anything serious obviously. 15 | */ 16 | #include "stdint.h" 17 | #include "main.h" 18 | 19 | #define FEE_START_ADDRESS ((uint32_t)0x0800F000) // FEE Start Address (in Flash Memory) 20 | #define FEE_PAGE_SIZE ((uint32_t)0x400) // FEE Page Size = 1kB (Default Page Size For STM32F103) 21 | #define FEE_BUFFER_LEN (FEE_PAGE_SIZE / 2U) 22 | 23 | //-----[ Prototypes For All User External Functions ]----- 24 | 25 | HAL_StatusTypeDef FEE_Write(uint32_t address, uint16_t *data, uint32_t dataSize); 26 | void FEE_Read(uint32_t address, uint16_t *data, uint32_t dataSize); 27 | 28 | // Generic APIs For Any Data Type 29 | void FEE_WriteData(uint32_t address, void *data, size_t dataSize); 30 | void FEE_ReadData(uint32_t address, void *data, size_t dataSize); 31 | 32 | #endif /* FEE_H_ */ 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # STM32_Course_DeepBlue 2 | STM32 Course Repo 3 | -------------------------------------------------------------------------------- /util/Util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Util.c 3 | * Driver Name: [[ Util ]] 4 | * SW Layer: UTIL 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | */ 11 | 12 | #include "Util.h" 13 | 14 | 15 | -------------------------------------------------------------------------------- /util/Util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Util.h 3 | * Driver Name: [[ Util ]] 4 | * SW Layer: Util 5 | * Created on: Jun 28, 2020 6 | * Author: Khaled Magdy 7 | * ------------------------------------------- 8 | * For More Information, Tutorials, etc. 9 | * Visit Website: www.DeepBlueMbedded.com 10 | */ 11 | 12 | #ifndef UTIL_H_ 13 | #define UTIL_H_ 14 | 15 | /* 16 | *--------------------------------------- 17 | * GPIO Direct Register Access Macros 18 | *--------------------------------------- 19 | */ 20 | 21 | #define GPIO_SET_PIN(port, pin) ((port)->BSRR = (pin)) 22 | #define GPIO_CLEAR_PIN(port, pin) ((port)->BSRR = (pin << 16u)) 23 | #define GPIO_TOGGLE_PIN(port, pin) ((port)->ODR ^= (pin)) 24 | #define GPIO_READ_PIN(port, pin) ((port)->IDR & (pin)) 25 | 26 | /* 27 | *--------------------------------------- 28 | * SysTick Timer Delay Macros 29 | *--------------------------------------- 30 | */ 31 | 32 | #define SYSTICK_LOAD (SystemCoreClock/1000000U) 33 | #define SYSTICK_DELAY_CALIB (SYSTICK_LOAD >> 1) 34 | 35 | #define DELAY_US(us) \ 36 | do { \ 37 | uint32_t start = SysTick->VAL; \ 38 | uint32_t ticks = (us * SYSTICK_LOAD)-SYSTICK_DELAY_CALIB; \ 39 | while((start - SysTick->VAL) < ticks); \ 40 | } while (0) 41 | 42 | #define DELAY_MS(ms) \ 43 | do { \ 44 | for (uint32_t i = 0; i < ms; ++i) { \ 45 | DELAY_US(1000); \ 46 | } \ 47 | } while (0) 48 | 49 | #endif /* UTIL_H_ */ 50 | --------------------------------------------------------------------------------