/** * @brief Main program * @param None * @retval None */ int main(void) { /* STM32F0xx HAL library initialization: - Configure the Flash prefetch - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Low Level Initialization */ uint32_t status = RCC_CRS_TIMEOUT; RCC_CRSSynchroInfoTypeDef syncinfo = {0}; RCC_CRSInitTypeDef crsinitstruct = {0}; HAL_Init(); /* Configure LED1 and LED3 */ BSP_LED_Init(LED1); BSP_LED_Init(LED3); /* Enable HSE oscillator and configure the PLL to reach the max system frequency (48 MHz) when using HSE oscillator as PLL clock source. */ SystemClock_Config(); /* CRS initialization (enable HSI48 and LSE oscillators and then enable CRS clock */ CRS_Init(); /* HSI48 Synchronization with LSE frequency */ crsinitstruct.Prescaler = RCC_CRS_SYNC_DIV1; crsinitstruct.Source = RCC_CRS_SYNC_SOURCE_LSE; crsinitstruct.Polarity = RCC_CRS_SYNC_POLARITY_FALLING; /* F(LSE)=32.768kHz then Reload=(f(Target)/f(LSE))-1= 0x5B7*/ crsinitstruct.ReloadValue = __HAL_RCC_CRS_CALCULATE_RELOADVALUE(48000000,32768); crsinitstruct.ErrorLimitValue = RCC_CRS_ERRORLIMIT_DEFAULT; /* Change the HSI trimming value to see the automatic calibration performed by CRS */ crsinitstruct.HSI48CalibrationValue = 0x00; /* Start automatic synchronization using polling mode */ HAL_RCCEx_CRSConfig(&crsinitstruct); /* Wait for synchronization OK event */ do { /* Check status of CRS synchronization */ /* Timeout is based on F(LSE) then less than 1 ms*/ status = HAL_RCCEx_CRSWaitSynchronization(1); if ((status & RCC_CRS_TIMEOUT) == RCC_CRS_TIMEOUT) { /* Timeout issue. May have a problem with synchronization frequency */ Error_Handler(); } /* Adapt synchronization input parameters in case of SYNC error or SYNC miss event */ if (((status & RCC_CRS_SYNCERR) == RCC_CRS_SYNCERR) || ((status & RCC_CRS_SYNCMISS) == RCC_CRS_SYNCMISS)) { HAL_RCCEx_CRSGetSynchronizationInfo(&syncinfo); /* User can check different parameters returned in synchronization info structure*/ /* and restart a new synchronization in changing input parameters */ HAL_RCCEx_CRSConfig(&crsinitstruct); } } while((status & RCC_CRS_SYNCOK) != RCC_CRS_SYNCOK); /* Power on LED1 */ BSP_LED_On(LED1); /* Infinite loop */ while (1) { } }
int __start(void) { const volatile uint32_t *src; volatile uint32_t *dest; /* Set up BSS and copy data from flash */ for (src = &_eronly, dest = &_sdata; dest < &_edata;) { *dest++ = *src++; } for (dest = &_sbss; dest < &_ebss;) { *dest++ = 0; } SystemInit(); HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Make sure the flash option bytes are set such that we don't re-enter bootloader mode */ set_dfu_option_bytes(0u); MX_USB_DEVICE_Init(); /* Configure GPIO for the CAN_SILENT signal */ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __GPIOA_CLK_ENABLE(); __GPIOB_CLK_ENABLE(); __CRS_CLK_ENABLE(); /*Configure GPIO pin : PB7 */ GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /**CAN GPIO Configuration PB8 ------> CAN_RX PB9 ------> CAN_TX */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_CAN; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* Configure the bxCAN transceiver */ CAN_HandleTypeDef hcan; __CAN_CLK_ENABLE(); hcan.Instance = CAN; hcan.Init.Mode = CAN_MODE_SILENT; hcan.Init.TTCM = DISABLE; hcan.Init.ABOM = ENABLE; hcan.Init.AWUM = ENABLE; hcan.Init.NART = DISABLE; hcan.Init.RFLM = DISABLE; hcan.Init.TXFP = DISABLE; /* Set the bitrate and init */ set_can_bitrate(&hcan, 1000000u); CanRxMsgTypeDef rx_msg; hcan.pRxMsg = &rx_msg; CanTxMsgTypeDef tx_msg; hcan.pTxMsg = &tx_msg; CAN_FilterConfTypeDef filter; filter.FilterNumber = 0; filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; filter.FilterActivation = ENABLE; filter.BankNumber = 0; filter.FilterMaskIdLow = filter.FilterIdLow = filter.FilterMaskIdHigh = filter.FilterIdHigh = 0; HAL_CAN_ConfigFilter(&hcan, &filter); __HAL_UNLOCK(&hcan); /* Now that USB is active, we need to sync with the 1 kHz SOF packets to tune the HSI48 so it's accurate enough not to disrupt the CAN bus. */ RCC_CRSInitTypeDef crs_config; crs_config.Prescaler = RCC_CRS_SYNC_DIV1; crs_config.Source = RCC_CRS_SYNC_SOURCE_USB; crs_config.Polarity = RCC_CRS_SYNC_POLARITY_RISING; crs_config.ReloadValue = RCC_CRS_RELOADVALUE_DEFAULT; crs_config.ErrorLimitValue = RCC_CRS_ERRORLIMIT_DEFAULT; crs_config.HSI48CalibrationValue = RCC_CRS_HSI48CALIBRATION_DEFAULT; HAL_RCCEx_CRSConfig(&crs_config); /* Don't continue unless we're synced */ while (!(HAL_RCCEx_CRSWaitSynchronization(1000000u) & RCC_CRS_SYNCOK)); while (1) { /* Set up the command record */ size_t i; uint8_t current_cmd; uint8_t current_cmd_data[32]; uint8_t current_cmd_data_length; uint8_t channel_open; current_cmd = current_cmd_data_length = i = 0; channel_open = 0; rx_buffer_length = 0; while (hUsbDevice_0 && hUsbDevice_0->pClassData) { /* If the RX buffer is non-empty, process any commands/messages in it and then acknowledge the transfer to the USB stack */ if (rx_buffer_length) { /* Exit if we've read the entire buffer, or if transmit mailboxes are full and the current command is a transmit. */ for (; i < rx_buffer_length && ((current_cmd != 't' && current_cmd != 'T') || __HAL_CAN_GET_FLAG(&hcan, CAN_FLAG_TME0)); i++) { if (rx_buffer[i] == '\r') { uint8_t *buf = active_buffer ? tx_buffer_1 : tx_buffer_0; /* End of command -- process and reset state */ switch (current_cmd) { case 'S': /* Setup bitrate -- data should be a number from 0 to 8. */ if (current_cmd_data[0] < '0' || current_cmd_data[0] > '8') { buf[active_buffer_length++] = '\a'; } else if (set_can_bitrate( &hcan, bitrate_lookup[current_cmd_data[0] - '0'])) { buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'O': /* Open channel -- take CAN out of silent mode and start receiving. */ if (!channel_open) { channel_open = 1; set_can_silent(&hcan, 0); buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'L': /* Open in listen-only -- CAN should already be in silent mode but just make sure. */ if (!channel_open) { channel_open = 1; set_can_silent(&hcan, 1); buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'C': /* Close channel -- put CAN back in silent mode. */ if (channel_open) { channel_open = 0; set_can_silent(&hcan, 1); buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'V': /* Hardware version */ buf[active_buffer_length++] = 'V'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '1'; buf[active_buffer_length++] = '\r'; break; case 'v': /* Major/minor version */ buf[active_buffer_length++] = 'v'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '0'; buf[active_buffer_length++] = '1'; buf[active_buffer_length++] = '\r'; break; case 'N': /* Serial number */ buf[active_buffer_length++] = 'N'; buf[active_buffer_length++] = 'F'; buf[active_buffer_length++] = 'F'; buf[active_buffer_length++] = 'F'; buf[active_buffer_length++] = 'F'; buf[active_buffer_length++] = '\r'; break; case 'T': /* Extended message */ if (read_ext_message(&tx_msg, current_cmd_data, current_cmd_data_length) && HAL_CAN_Transmit(&hcan, 0) == HAL_OK) { buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 't': /* Standard message */ if (read_std_message(&tx_msg, current_cmd_data, current_cmd_data_length) && HAL_CAN_Transmit(&hcan, 0) == HAL_OK) { buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'R': /* Extended RTR */ if (read_ext_rtr(&tx_msg, current_cmd_data, current_cmd_data_length) && HAL_CAN_Transmit(&hcan, 0) == HAL_OK) { buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case 'r': /* Standard RTR */ if (read_std_rtr(&tx_msg, current_cmd_data, current_cmd_data_length) && HAL_CAN_Transmit(&hcan, 0) == HAL_OK) { buf[active_buffer_length++] = '\r'; } else { buf[active_buffer_length++] = '\a'; } break; case '_': /* Bootloader request */ if (current_cmd_data[0] == '_' && current_cmd_data[1] == 'd' && current_cmd_data[2] == 'f' && current_cmd_data[3] == 'u') { /* Set option bytes to force bootloader entry */ set_dfu_option_bytes(1u); NVIC_SystemReset(); } else { buf[active_buffer_length++] = '\a'; } break; case 'F': /* Read status flags -- return 4 hex digits */ case 'Z': /* Timestamp on/off -- 0=off, 1=on */ case 'M': /* Acceptance mask -- 8 hex digits */ case 'm': /* Acceptance value -- 8 hex digits */ case 's': /* Set bitrate register -- 6 hex digits */ default: /* NACK */ buf[active_buffer_length++] = '\a'; break; } current_cmd = current_cmd_data_length = 0; } else if (current_cmd) { /* Command data -- save it */ current_cmd_data[current_cmd_data_length++] = rx_buffer[i]; /* Reset command state if the data is too long */ if (current_cmd_data_length == 32u) { current_cmd = current_cmd_data_length = 0; } } else { /* The first letter of a line is the command type -- don't bother validating as we can't NACK until the data has been received. */ current_cmd = rx_buffer[i]; } } if (i == rx_buffer_length) { /* Mark last packet as received */ rx_buffer_length = i = 0; USBD_CDC_ReceivePacket(hUsbDevice_0); } } /* Check the CAN controller for messages and process them if the channel is open */ if (HAL_CAN_Receive(&hcan, CAN_FIFO0, 0) == HAL_OK && hUsbDevice_0 && channel_open) { /* Format the message and send it to the host. The data format for a standard ID message is: tiiildddddddddddddddd\r The data format for a standard ID RTR is: riii\r The data format for an extended ID message is: Tiiiiiiiildddddddddddddddd\r The data format for an extended ID RTR is: Riiiiiiii\r */ uint8_t *write_location; if (active_buffer_length + EXT_MESSAGE_LEN > TX_BUFFER_SIZE) { /* Reset buffer if we're too far behind -- use worst-case message length for calculation */ active_buffer_length = 0; } write_location = &((active_buffer ? tx_buffer_1 : tx_buffer_0)[active_buffer_length]); if (rx_msg.IDE == CAN_ID_EXT && rx_msg.RTR) { active_buffer_length += write_ext_rtr( write_location, &rx_msg); } else if (rx_msg.IDE == CAN_ID_EXT && !rx_msg.RTR) { active_buffer_length += write_ext_message( write_location, &rx_msg); } else if (rx_msg.IDE == CAN_ID_STD && rx_msg.RTR) { active_buffer_length += write_std_rtr( write_location, &rx_msg); } else if (rx_msg.IDE == CAN_ID_STD && !rx_msg.RTR) { active_buffer_length += write_std_message( write_location, &rx_msg); } } if (!hUsbDevice_0 || !hUsbDevice_0->pClassData) { /* Reset TX buffer if USB is not connected */ active_buffer_length = 0; } else if (active_buffer_length && ((USBD_CDC_HandleTypeDef*)hUsbDevice_0->pClassData)->TxState == 0) { /* Transmit the next buffer if one is available */ CDC_Transmit_FS(active_buffer ? tx_buffer_1 : tx_buffer_0, active_buffer_length); active_buffer_length = 0; active_buffer = active_buffer ? 0 : 1; } } } }