/** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_SPI4_Init(); /* USER CODE BEGIN 2 */ InitTraces(); TRACE_INIT("\n\n\rLCB code version %X release %X\r\n", 1, 0); TRACE_INIT("Code build %s %s\r\n", __DATE__, __TIME__); // Initialize Real Time Clock management ddi_rtc_init(); //initialize EEprom module ddi_eeprom_init(); // Read statistics and errors from EEPROM App_error_statitics_init(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ App_Task_StartInitialTasks(&applicationTasks[0]); App_Task_StartRemainingTasks(&applicationTasks[0]); TRACE_INIT("Init Done\n"); vTaskStartScheduler(); while (1) { // Control should be taken by scheduler, so reaching this point is a critical failure. vTaskSuspendAll(); vTaskEndScheduler(); Error_Handler(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * Enable DMA controller clock */ void MX_DMA_Init(void) { /* Init with LL driver */ /* DMA controller clock enable */ LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ NVIC_SetPriority(DMA2_Stream0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),10, 0)); NVIC_EnableIRQ(DMA2_Stream0_IRQn); /* DMA2_Stream3_IRQn interrupt configuration */ NVIC_SetPriority(DMA2_Stream3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),9, 0)); NVIC_EnableIRQ(DMA2_Stream3_IRQn); /* DMA2_Stream4_IRQn interrupt configuration */ NVIC_SetPriority(DMA2_Stream4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),9, 0)); NVIC_EnableIRQ(DMA2_Stream4_IRQn); } /* SPI4 init function */ void MX_SPI4_Init(void) { /* USER CODE BEGIN SPI4_Init 0 */ /* USER CODE END SPI4_Init 0 */ LL_SPI_InitTypeDef SPI_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Peripheral clock enable */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI4); LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOE); /**SPI4 GPIO Configuration PE12 ------> SPI4_SCK PE13 ------> SPI4_MISO PE14 ------> SPI4_MOSI */ GPIO_InitStruct.Pin = SPI4_EEPROM_CLK_Pin|SPI4_EEPROM_MISO_Pin|SPI4_EEPROM_MOSI_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; GPIO_InitStruct.Alternate = LL_GPIO_AF_5; LL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* SPI4 DMA Init */ /* SPI4_RX Init */ LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_3, LL_DMA_CHANNEL_5); LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY); LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_3, LL_DMA_PRIORITY_MEDIUM); LL_DMA_SetMode(DMA2, LL_DMA_STREAM_3, LL_DMA_MODE_NORMAL); LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_3, LL_DMA_PERIPH_NOINCREMENT); LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_3, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_3, LL_DMA_MDATAALIGN_BYTE); LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_3); /* SPI4_TX Init */ LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_4, LL_DMA_CHANNEL_5); LL_DMA_SetDataTransferDirection(DMA2, LL_DMA_STREAM_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); LL_DMA_SetStreamPriorityLevel(DMA2, LL_DMA_STREAM_4, LL_DMA_PRIORITY_MEDIUM); LL_DMA_SetMode(DMA2, LL_DMA_STREAM_4, LL_DMA_MODE_NORMAL); LL_DMA_SetPeriphIncMode(DMA2, LL_DMA_STREAM_4, LL_DMA_PERIPH_NOINCREMENT); LL_DMA_SetMemoryIncMode(DMA2, LL_DMA_STREAM_4, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMA2, LL_DMA_STREAM_4, LL_DMA_PDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMA2, LL_DMA_STREAM_4, LL_DMA_MDATAALIGN_BYTE); LL_DMA_DisableFifoMode(DMA2, LL_DMA_STREAM_4); /* SPI4 interrupt Init */ NVIC_SetPriority(SPI4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),10, 0)); NVIC_EnableIRQ(SPI4_IRQn); /* USER CODE BEGIN SPI4_Init 1 */ /* USER CODE END SPI4_Init 1 */ SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW; SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE; SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32; SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; SPI_InitStruct.CRCPoly = 10; LL_SPI_Init(SPI4, &SPI_InitStruct); LL_SPI_SetStandard(SPI4, LL_SPI_PROTOCOL_MOTOROLA); /* USER CODE BEGIN SPI4_Init 2 */ /* USER CODE END SPI4_Init 2 */ } /*************************************************** * Local variables Section ***************************************************/ static SPI_TypeDef * pSPI_Instance; static DMA_TypeDef * pDMA_SPI_Instance; static uint32_t InputStreamNumber; static uint32_t OutputStreamNumber; static StaticSemaphore_t StaticEEPromMutex; static SemaphoreHandle_t EEPromMutexHandle; static bool TransferDone; static StaticSemaphore_t TransferDoneSemaphore; static SemaphoreHandle_t TransferDoneSemaphoreHandle; static uint8_t SendBuffer[256]; static uint8_t RecvBuffer[256]; /********************************************************************************************************************* * Types ********************************************************************************************************************/ /********************************************************************************************************************* * Private functions prototype ********************************************************************************************************************/ /********************************************************************************************************************* * Functions definition ********************************************************************************************************************/ #define SPI4_EEPROM_nCS_GPIO_Port GPIOE #define SPI4_EEPROM_nCS_Pin LL_GPIO_PIN_11 static void EEprom_CS_enable(void) { LL_GPIO_ResetOutputPin( SPI4_EEPROM_nCS_GPIO_Port, SPI4_EEPROM_nCS_Pin ); } static void EEprom_CS_disable(void) { LL_GPIO_SetOutputPin( SPI4_EEPROM_nCS_GPIO_Port, SPI4_EEPROM_nCS_Pin ); } /** * @brief EEPROM init * @param[in] void * @retval None */ void ddi_eeprom_init( void ) { //ddi_eeprom_init_model(); pSPI_Instance = SPI4; pDMA_SPI_Instance = DMA2; // Peripheral to memory InputStreamNumber = LL_DMA_STREAM_3; // Memory to peripheral OutputStreamNumber = LL_DMA_STREAM_4; // Create the mutex for EEPROM EEPromMutexHandle = xSemaphoreCreateMutexStatic ( &StaticEEPromMutex ); // Create the semaphore for read/write done TransferDoneSemaphoreHandle = xSemaphoreCreateBinaryStatic ( &TransferDoneSemaphore ); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, InputStreamNumber, (uint32_t) &pSPI_Instance->DR); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, OutputStreamNumber, (uint32_t) &pSPI_Instance->DR); // Enable Transfer error interrupt LL_DMA_EnableIT_TE(pDMA_SPI_Instance, InputStreamNumber); // Enable Transfer complete interrupt LL_DMA_EnableIT_TC(pDMA_SPI_Instance, InputStreamNumber); // Enable Direct Mode error interrupt LL_DMA_EnableIT_DME(pDMA_SPI_Instance, InputStreamNumber); // Enable Transfer error interrupt LL_DMA_EnableIT_TE(pDMA_SPI_Instance, OutputStreamNumber); // Enable Transfer complete interrupt LL_DMA_EnableIT_TC(pDMA_SPI_Instance, OutputStreamNumber); // Enable Direct Mode error interrupt LL_DMA_EnableIT_DME(pDMA_SPI_Instance, OutputStreamNumber); // Enable SPI err interrupt LL_SPI_EnableIT_ERR(pSPI_Instance); } uint32_t SPI_Error = 0; uint32_t UnderrunError = 0; uint32_t CRCError = 0; uint32_t ModeFaultError = 0; uint32_t OverrunError = 0; uint32_t FormatError = 0; void SPI4_IRQHandler(void) { uint32_t ErrorFlags; ErrorFlags = pSPI_Instance->SR; if( ( ErrorFlags & (SPI_SR_UDR|SPI_SR_CRCERR|SPI_SR_MODF|SPI_SR_OVR|SPI_SR_FRE) ) != 0 ) { ++SPI_Error; // If underrun error if( ErrorFlags & SPI_SR_UDR ) { TRACE_SPI_INT("--%s Underrun\n",__FUNCTION__); ++UnderrunError; // Reset error condition uint32_t data = pSPI_Instance->DR; data = pSPI_Instance->SR; } // If CRC error if( ErrorFlags & SPI_SR_CRCERR ) { TRACE_SPI_INT("--%s CRC error\n",__FUNCTION__); ++CRCError; } // If Mode Fault if( ErrorFlags & SPI_SR_MODF ) { TRACE_SPI_INT("--%s Mode fault\n",__FUNCTION__); ++ModeFaultError; } // If Overrun Flag if( ErrorFlags & SPI_SR_OVR ) { TRACE_SPI_INT("--%s Overrun\n",__FUNCTION__); ++OverrunError; // Reset error condition uint32_t data = pSPI_Instance->DR; data = pSPI_Instance->SR; } // Frame format error flag if( ErrorFlags & SPI_SR_FRE ) { TRACE_SPI_INT("--%s Format error\n",__FUNCTION__); ++FormatError; } } } // DMA used to receive datas from EEPROM to memory void DMA2_Stream3_IRQHandler(void) { TRACE_SPI_INT("--%s\n",__FUNCTION__); uint32_t Status = pDMA_SPI_Instance->LISR; int i = 0; // Stream transfer error interrupt flag if( Status & DMA_LISR_TEIF3 ) { ++i; } // Stream transfer complete interrupt if( Status & DMA_LISR_TCIF3 ) { TransferDone = true; // Post semaphore when the transfer is done xSemaphoreGiveFromISR ( TransferDoneSemaphoreHandle, NULL ); } // DMA direct mode error interrupt if( Status & DMA_LISR_DMEIF3 ) { ++i; } // DMA FIFO error interrupt if( Status & DMA_LISR_FEIF3 ) { ++i; } WRITE_REG(pDMA_SPI_Instance->LIFCR, Status); } // DMA used to send datas from memory to EEPROM void DMA2_Stream4_IRQHandler(void) { uint32_t Status = pDMA_SPI_Instance->HISR; uint32_t i = 0; TRACE_SPI_INT("--%s\n",__FUNCTION__); // Stream transfer error interrupt flag if( Status & DMA_HISR_TEIF4 ) { // Clear flag TEIFx ++i; } // Stream transfer complete interrupt if( Status & DMA_HISR_TCIF4 ) { TransferDone = true; // Post semaphore when the transfer is done xSemaphoreGiveFromISR ( TransferDoneSemaphoreHandle, NULL ); } // DMA direct mode error interrupt if( Status & DMA_HISR_DMEIF4 ) { ++i; } // DMA FIFO error interrupt if( Status & DMA_HISR_FEIF4 ) { ++i; } WRITE_REG(pDMA_SPI_Instance->HIFCR, Status); } memory_status_t read(uint8_t * pData, uint32_t length) { int i; TRACE_SPI(">>%s %Xh for %d\n",__FUNCTION__,pData,length); // Disable SPI LL_SPI_Disable(pSPI_Instance); // Disable DMA streams LL_DMA_DisableStream(pDMA_SPI_Instance, OutputStreamNumber); LL_DMA_DisableStream(pDMA_SPI_Instance, InputStreamNumber); // Disable DMA RX LL_SPI_DisableDMAReq_RX(pSPI_Instance); // Disable DMA TX LL_SPI_DisableDMAReq_TX(pSPI_Instance); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, InputStreamNumber, (uint32_t) &pSPI_Instance->DR); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, OutputStreamNumber, (uint32_t) &pSPI_Instance->DR); LL_DMA_SetMemoryAddress(pDMA_SPI_Instance, InputStreamNumber, (uint32_t) pData); LL_DMA_SetDataLength(pDMA_SPI_Instance, InputStreamNumber, length); LL_DMA_SetMemoryAddress(pDMA_SPI_Instance, OutputStreamNumber, (uint32_t) SendBuffer); LL_DMA_SetDataLength(pDMA_SPI_Instance, OutputStreamNumber, length); /* Clear all interrupt flags at correct offset within the register */ WRITE_REG(pDMA_SPI_Instance->LIFCR, DMA_LIFCR_CHTIF3|DMA_LIFCR_CTCIF3|DMA_LIFCR_CTEIF3|DMA_LIFCR_CDMEIF3|DMA_LIFCR_CFEIF3); WRITE_REG(pDMA_SPI_Instance->HIFCR, DMA_HIFCR_CHTIF4|DMA_HIFCR_CTCIF4|DMA_HIFCR_CTEIF4|DMA_HIFCR_CDMEIF4|DMA_HIFCR_CFEIF4); // Enable input stream LL_DMA_EnableStream(pDMA_SPI_Instance, InputStreamNumber); // Enable DMA RX LL_SPI_EnableDMAReq_RX(pSPI_Instance); TransferDone = false; // Reset semaphore xSemaphoreTake ( TransferDoneSemaphoreHandle, 0 ); // Enable output stream LL_DMA_EnableStream(pDMA_SPI_Instance, OutputStreamNumber); // Enable the SPI peripheral LL_SPI_Enable(pSPI_Instance); // Enable DMA TX LL_SPI_EnableDMAReq_TX(pSPI_Instance); // If scheduler is running if ( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) { // Wait until the interrupt indicates transfer done. for( i = 0 ; i < 10 ; ++i ) { // Wait for SPI transfer done if ( xSemaphoreTake ( TransferDoneSemaphoreHandle, 150/*portMAX_DELAY*/ ) == pdPASS ) { TRACE_SPI("<<%s OK\n",__FUNCTION__); return( MEMORY_STATUS_OK ); } } } else { for( i = 1 ; i < 0xFFFFF ; ++i ) { if( TransferDone == true ) { return( MEMORY_STATUS_OK ); } if( ! LL_SPI_IsActiveFlag_BSY(pSPI_Instance) ) { TRACE_SPI("<<%s OK\n",__FUNCTION__); return( MEMORY_STATUS_OK ); } } } // Disable SPI LL_SPI_Disable(pSPI_Instance); TRACE_SPI("<<%s NOK\n",__FUNCTION__); return MEMORY_STATUS_NOK; } memory_status_t write(uint8_t * pData, uint32_t length) { int i; TRACE_SPI(">>%s %Xh for %d\n",__FUNCTION__,pData,length); // Disable SPI LL_SPI_Disable(pSPI_Instance); // Disable DMA streams LL_DMA_DisableStream(pDMA_SPI_Instance, OutputStreamNumber); LL_DMA_DisableStream(pDMA_SPI_Instance, InputStreamNumber); // Disable DMA RX LL_SPI_DisableDMAReq_RX(pSPI_Instance); // Disable DMA TX LL_SPI_DisableDMAReq_TX(pSPI_Instance); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, InputStreamNumber, (uint32_t) &pSPI_Instance->DR); LL_DMA_SetPeriphAddress(pDMA_SPI_Instance, OutputStreamNumber, (uint32_t) &pSPI_Instance->DR); // Configure data address and length LL_DMA_SetMemoryAddress(pDMA_SPI_Instance, OutputStreamNumber, (uint32_t) pData); LL_DMA_SetDataLength(pDMA_SPI_Instance, OutputStreamNumber, length); LL_DMA_SetMemoryAddress(pDMA_SPI_Instance, InputStreamNumber, (uint32_t) RecvBuffer); LL_DMA_SetDataLength(pDMA_SPI_Instance, InputStreamNumber, length); /* Clear all interrupt flags at correct offset within the register */ WRITE_REG(pDMA_SPI_Instance->LIFCR, DMA_LIFCR_CHTIF3|DMA_LIFCR_CTCIF3|DMA_LIFCR_CTEIF3|DMA_LIFCR_CDMEIF3|DMA_LIFCR_CFEIF3); WRITE_REG(pDMA_SPI_Instance->HIFCR, DMA_HIFCR_CHTIF4|DMA_HIFCR_CTCIF4|DMA_HIFCR_CTEIF4|DMA_HIFCR_CDMEIF4|DMA_HIFCR_CFEIF4); // Enable input stream LL_DMA_EnableStream(pDMA_SPI_Instance, InputStreamNumber); // Enable DMA RX LL_SPI_EnableDMAReq_RX(pSPI_Instance); TransferDone = false; // Reset semaphore xSemaphoreTake ( TransferDoneSemaphoreHandle, 0 ); // Enable output stream LL_DMA_EnableStream(pDMA_SPI_Instance, OutputStreamNumber); // Enable the SPI peripheral LL_SPI_Enable(pSPI_Instance); // Enable DMA TX LL_SPI_EnableDMAReq_TX(pSPI_Instance); // If scheduler is running if ( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) { // Wait until the interrupt indicates transfer done. for( i = 0 ; i < 5 ; ++i ) { // Wait for SPI transfer done if ( xSemaphoreTake ( TransferDoneSemaphoreHandle, 150/*portMAX_DELAY*/ ) == pdPASS ) { TRACE_SPI("<<%s OK\n",__FUNCTION__); return( MEMORY_STATUS_OK ); } } } else { for( i = 1 ; i < 0xFFFFFF ; ++i ) { if( TransferDone == true ) { return( MEMORY_STATUS_OK ); } if( ! LL_SPI_IsActiveFlag_BSY(pSPI_Instance) ) { TRACE_SPI("<<%s OK\n",__FUNCTION__); return( MEMORY_STATUS_OK ); } } } // Disable SPI LL_SPI_Disable(pSPI_Instance); TRACE_SPI("<<%s NOK\n",__FUNCTION__); return MEMORY_STATUS_NOK; } memory_status_t EEprom_write_latch_enable(void) { uint8_t enable = WRITE_ENABLE; memory_status_t rc; EEprom_CS_enable(); rc = write(&enable, 1); EEprom_CS_disable(); HAL_Delay(5); return rc; } memory_status_t EEprom_write_latch_disable(void) { uint8_t disable = WRITE_DISABLE; memory_status_t rc; EEprom_CS_enable(); rc = write(&disable, 1); EEprom_CS_disable(); HAL_Delay(5); return rc; } memory_status_t cat25256_read(uint32_t address, uint32_t *data, uint32_t length) { memory_status_t rc; uint8_t header[3] = {0}; uint8_t rxBuffer[4] = {0}; header[0] = READ_EEPROM; header[1] = address >> 8; header[2] = address & 0xFF; EEprom_CS_enable(); if (write(header, sizeof header) != MEMORY_STATUS_OK) { EEprom_CS_disable(); return MEMORY_STATUS_NOK; } rc = read(rxBuffer, sizeof rxBuffer); EEprom_CS_disable(); HAL_Delay(5); *data = (rxBuffer[0] << 24 ) + (rxBuffer[1] << 16 ) + ( rxBuffer[2] << 8 ) + rxBuffer[3]; return rc; } memory_status_t cat25256_write(uint32_t address, uint32_t data, uint32_t length) { memory_status_t rc; uint8_t header[3] = {0}; uint8_t data_buff[4] = {0}; header[0] = WRITE_EEPROM; header[1] = address >> 8; header[2] = address & 0xFF; data_buff[0] = ( data >> 24 ) & 0xFF; data_buff[1] = ( data >> 16 ) & 0xFF; data_buff[2] = ( data >> 8 ) & 0xFF; data_buff[3] = data & 0xFF; // Send the command to enable the "write mode" EEprom_write_latch_enable(); EEprom_CS_enable(); if (write(header, sizeof header) != MEMORY_STATUS_OK) { EEprom_CS_disable(); return MEMORY_STATUS_NOK; } // Send datas rc = write(data_buff, sizeof data_buff); EEprom_CS_disable(); HAL_Delay(5); return rc; }