I have a board that is connected to USB on a STM32F107 with the following pins
USB_OTG_VBUS : PA9
USBDM : PA11
USBDP : PA12
I have a project that needs to use both Virtual Com Port and USB Mass Storage. It needs to re-enumerate the USB then do a software reset to enable the different USB class.
I have tried various different things to get it to re-enumerate but so far have been unable to, the only way to re-enumerate is to unplug usb cable.
These are some of the functions i have tried with no success
USB_OTG_DisableGlobalInt(&USB_OTG_dev);
USB_OTG_WRITE_REG32(&USB_OTG_dev.regs.GREGS->GINTSTS, 0xBFFFFFFF);
USB_OTG_CoreReset(&USB_OTG_dev);
USBD_DeInit(&USB_OTG_dev);
DCD_DevDisconnect(&USB_OTG_dev);
NVIC_SystemReset();
Would anyone have any ideas on how to get the USB to re-enumerate when it is configured with only these 3 pins for the STM32F107?
If you're using a demo board, it has the functionality to disconnect the USB through a microcontroller pin. If you're not using a demo board, you need to come up with that ability yourself, by disconnecting the pull-up resistor on the USB_DM/USB_DP line...
Before initializing USB peripheral, configure D+ pin (USBP) as GPIO output push-pull and set low (0V) for 5ms. Then initiate standard USB configuration including GPIO. After this procedure USB host recognizes new device and starts enumeration.
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_12);
delay_ms(5);
//call your USB Init here
Worked for me.
source
Had a similar problem. Try this:
USB_OTG_dev.regs.GREGS->GCCFG = 0;
Wait a bit and then init the USB again.
I used the answer from #viteo and tweaked it a little as I had some compile errors. This code works on the Blue Pill development board (STM32F103C8), which includes a 1.5k pullup resistor on the PA12 (USB_DP) line. Therefore, this code forces the USB_DP line low for a short time, which is like the USB cable has been unplugged and reconnected, thereby forcing the host to re-enumerate the bus when the USB is subsequently configured.
Edit USB_DEVICE/App/usb_device.c and add the code inside the USB_DEVICE_Init_PreTreatment block
void MX_USB_DEVICE_Init(void)
{
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(100);
/* USER CODE END USB_DEVICE_Init_PreTreatment */
Related
I was having trouble on the STM32L462xx with setting the device up for flashing over USB without having access to the BOOT0 pin. Going off of the tutorial on the ST site didn't seem to accomplish the task. Has anyone successfully set the STM32L4 into bootloader mode from software?
https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
I was able to set the device into a mode which it can be programmed with STM32Cube Programmer or the DFU-util program using the following code. This is partly a signal boost for this programmers solution which went against the ST tutorial on their site saying how to put jump the device memory to bootloader for USB programming
https://github.com/markusgritsch/SilF4ware/blob/94bb679119a0b9879fedc62a5e22f40623433242/SilF4ware/drv_reset.c
void jump_to_bootloader(void)
{
__enable_irq();
HAL_RCC_DeInit();
HAL_DeInit();
SysTick->CTRL = SysTick->LOAD = SysTick->VAL = 0;
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
const uint32_t p = (*((uint32_t *) 0x1FFF0000));
__set_MSP( p );
void (*SysMemBootJump)(void);
SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
SysMemBootJump();
while( 1 ) {}
}
I have an ATTiny that is supposed to receive commands over UART. I have a simple display of eight LEDs that should show the contents of the most recent byte received. I am using an interrupt to read data as it is received. No matter what data I send UDR always reads 0xFF in the interrupt. I know the interrupt is being triggered since the display changes from 0x00 to 0xFF, but it never displays the value I sent over the serial bus.
This is how I enable UART.
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
This is the code in the interrupt. I have tested display() and it functions correctly on its own thus implying message is always 0xFF.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
I am confident that my computer is sending the correct information, but I have only tested it with a pseudo-terminal to print out the sent bytes. I intend to snoop the hardware connection with an oscilloscope, but I don't believe that is the issue. Is there something that is causing UDR to always read as 0xFF?
Edit:
I have snooped the connection with an oscilloscope and have verified that the computer is sending the correct data, at the correct rate. However, the ATTiny is not operating at the correct baud rate. At 2400 baud pulses should be about 400 microseconds long, however the microcontroller is producing pulses over 3 milliseconds long. This explains why it would always read 0xFF, the computer would send nearly the entire byte when the controller thought it was receiving the start bit, when the controller tried to read the remaining data the lines would be undriven, resulting in it reading all ones. I still don't know why this is the case as I believe I am properly setting the baud rate on the controller.
Edit:
The issue has been resolved. By default the clock prescaler is set to 8, so the device was only operating at 1MHz, not 8MHz. Setting the clock prescaler to 1 solved the problem.
There can be several problems with uart communication. First check some things:
Is controller configured with the right clock?
Internal/External
Is F_CPU defined for <util/setbaud.h>?
Is BAUD defined for <util/setbaud.h>?
Are you using a controller like ATmega16 that has special register access?
If you are using an external clock (that should not be devided) is CKDIV8 disabled in FUSES or in special registers at some controllers?
Is:
Baudrate,
Paritybit,
Stopbit
setup corret on Transmitter and Receiver
Debug:
If you are using a PC for communication, create a loopback at the UART adapter and check with a terminal (TeraTerm, Putty, ...) if the messages you send are received correctly.
You also can enable the TX controller and check if loopback is working on your uC.
If it is possible try to write the received data to some leds to check if some date is received
Is GND betweend receiver and transmitter connected?
Are the voltage levels between transmitter and receiver the same?
Do transmitter and receiver have its own source? (Then do not connect VCC!)
Check if the clock on the controller is correct (switch on an led with _delay_ms() function every second)
Example Program
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
Please explain what the display() function is doing...
I would like to use the pin PC3 as an external interrupt. Whenever I enable the interrupt I end up in the infinite loop.
This is how I init a gpio and its interrupt:
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
I have checked hardware and all signals are like they should be.
I tried PB0 and PC3 and the result is the same.
Anyone who knows how to play with stm32l4 and exti?
The infinite loop:
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
I dont even reach an interrupt here (I have a break point there)
void EXIT3_IRQnHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
if(!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_3))
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
}
EXTI_ClearITPendingBit(EXTI3_IRQn);
}
Maybe that is important to mention that I also have SPI configuration in the same project (SPI1).
If ISR name is not correct it will use some default error code (its name depends on configuration), as happens in your case.
In my code its named EXTI3_IRQHandler not EXTI3_IRQnHandler.
Check in your startup file (in my setup it is called startup_stm32l432xx.s) for ISR names to be used.
Currently, I am working on optimizing current consumption by using STOP Mode of the STM32L053C6T6 processor.
I'm facing a problem that I can not get through, and I'm very happy if you can help.
First of all, I would like to explain the algorithm in a very simplified way.
In the while loop, I print to Pc "STARTED" through the UART-Serial converter. Next, I set the RTC alarm to 10 seconds later. And the finally I sleep the MCU by using STOP MODE. After 10 seconds, MCU wakes up properly. So far everything is normal. After MCU wake up, I call the System Clock Config function. I print "woken-up" on the PC screen through UART. I can work this way forever But I do not like the current that circuit consume.
To reduce the power consumption, I set all the pins to analog before entering sleep mode. this method worked very well on reducing current consumption. But after all the pins are analog and MCU goes sleep and wake up, the MCU can not send to string to PC. I think UART Module does not work properly...
But I/O's and systick timer are running. I can understand this by toggling the LED in a certain delay(with HAL_DELAY)
Why I can not make it work with reinit all peripherals?
Here is my main code
int main(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_RTC_Init();
MX_TIM22_Init();
MX_USART1_UART_Init()
MX_USART2_UART_Init();;
Init_RTC();
HAL_Delay(500);
while(1)
{
printf("Started\n\r");
for(uint16_t count1 = 0;count1<25;count1++){
HAL_GPIO_TogglePin(STATE_LED0_GPIO_Port,STATE_LED0_Pin);
HAL_Delay(25);
}
SetAlarm(10);
EnterStopMode();
printf("Woken-Up\n\r");
HAL_Delay(1000);
}
}
void EnterStopMode(void){
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Disable GPIOs clock */
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
// STOP Moda girme komutu
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
HAL_Delay(1000);
SystemClock_Config();
HAL_Delay(500);
MX_GPIO_Init();
MX_USART2_UART_Init();
Solved
Well, I checked the Hal functions line by line. And I saw that after first peripheral initialization (uart,i2c,adc etc.), Hal functions do not allow re-init again by checking that particular peripherals instant state.
For example, In HAL_UART_Init(&huart2) function, In order to Init the low level hardware: (GPIO,CLOCK) the instant uart modules state must be UART_STATE_RESET.
In here
if(huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
}
To overcome this problem, I reset that particular state of peripheral init. Because without not clearing those flags, uart init functions does not enter HAL_UART_MspInit(huart);
I know that is bulky solution, but it works for now.
void EnterStopMode(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Configure all GPIO port pins in Analog Input mode (floating input trigger OFF) */
GPIO_InitStruct.Pin = GPIO_PIN_All;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Disable GPIOs clock */
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
HAL_TIM_Base_Stop_IT(&htim22);
HAL_ADC_Stop_IT(&hadc);
/* Enter Stop Mode */
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
/* init the SYS Clocks */
SystemClock_Config();
/*Init IO's */
MX_GPIO_Init();
/* Clear Peripheral States for MspInit *7
huart1.gState = HAL_UART_STATE_RESET;
huart2.gState = HAL_UART_STATE_RESET;
hi2c1.State = HAL_I2C_STATE_RESET;
hadc.State = HAL_ADC_STATE_RESET;
MX_USART2_UART_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_RTC_Init();
MX_TIM22_Init();
MX_ADC_Init();
HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
}
I am working on a NUCLEO-L476RG board, trying to start the bootloader from my firmware code but its not working for me. here is the code that i am trying to execute :
#include "stm32l4xx.h"
#include "stm32l4xx_nucleo.h"
#include "core_cm4.h"
#include "stm32l4xx_hal_uart.h"
GPIO_InitTypeDef GPIO_InitStructure;
UART_HandleTypeDef UartHandle;
UART_InitTypeDef UART_InitStructre;
void BootLoaderInit(uint32_t BootLoaderStatus){
void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
if(BootLoaderStatus == 1) {
HAL_DeInit(); // shut down running tasks
// Reset the SysTick Timer
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL =0;
__set_PRIMASK(1); // Disable interrupts
__set_MSP((uint32_t*) 0x20001000);
SysMemBootJump();
}
}
int main(void)
{
HAL_Init();
__GPIOC_CLK_ENABLE();
GPIO_InitStructure.Pin = GPIO_PIN_13;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
while (1) {
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)) {
BootLoaderInit(1);
}
}
return 0;
}
What i hope to get after the execution of the firmware is that i can connect to the board with a UART and send commands/get responses from the bootloader. the commands i am trying to use come from here: USART protocol used in the STM32 bootloader.
I don't see and response from the board after connecting with the UART.
Here are some ideas taken from the answers to this question.
HAL_RCC_DeInit();
This is apparently needed to put the clocks back into the state after reset, as the bootloader expects them to be.
__HAL_REMAPMEMORY_SYSTEMFLASH();
Maps the system bootloader to address 0x00000000
__ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
Set the stack pointer from bootloader ROM. Where does your 0x20001000 come from? If it's an arbitrary value, then the stack can clobber the bootloader's variables.
Then there is this alternate solution:
When I want to jump to the bootloader, I write a byte in one of the
backup register and then issue a soft-reset. Then, when the processor
will restart, at the very beginning of the program, it will read this
register.
Note that you need LSI or LSE clock for accessing the backup registers.
Try to avoid using __set_MSP(), as current implementation of this function does NOT allow you to change MSP if it is also the stack pointer which you currently use (and you most likely are). The reason is that this function marks "sp" as clobbered register, so it will be saved before and restored afterwards.
See here - STM32L073RZ (rev Z) IAP jump to bootloader (system memory)
Find your bootloader start address from the reference manual.
Then use the following code.
Make sure you have cleaned and disabled the interrupts before do so.
/* Jump to different address */
JumpAddress = *(__IO uint32_t*) (BootloaderAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
Please have a look at Official STM32 AppNote as well.