Browse over 10,000 Electronics Projects

Development Board for the STM32F042

Development Board for the STM32F042

Testing USB

stm32plus currently only has support for USB on the F4 which means that to test the USB interface I’m going to have to hold my nose and dive into that horrendous unreadable mess that’s otherwise known as the STM32 HAL. Taking the ‘custom HID’ example as a starting point, I proceeded to adapt it from the F072 target to the F042 and here’s some lessons I picked up along the way.

Remap PA11 and PA12 to USB_DP and USB_DM

When the MCU starts up PA11 and PA12 are configured for GPIO. The USB D+ and D- lines are actually on PA9 and PA10 and you need to map these two pins in place of PA11 or PA12. If you fail to do this then the USB interrupt will never fire. Here’s how:

// Remap PA11-12 to PA9-10 for USB

RCC->APB2ENR |= RCC_APB2ENR_SYSCFGCOMPEN;
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;

Way back in this article I promised to show you how to clock the MCU from the internal HSI48 oscillator and then use the SOF frames sent every 1ms by the host to continuously trim the clock to stay in sync with the host. Clocking your MCU like this means that you don’t have to use an external crystal which cuts costs and reduces board space.

Here’s the replacement SetSysClock() function that you can plug into System.c.



Advertisement1



void SetSysClock() {

  // enable flash prefetch buffer

  FLASH->ACR |= FLASH_ACR_PRFTBE;

  // enable HSI48

  RCC->CR2 |= RCC_CR2_HSI48ON;
  while((RCC->CR2 & RCC_CR2_HSI48RDY)==0);

  // disable the PLL

  RCC->CR &=~ RCC_CR_PLLON;
  while((RCC->CR & RCC_CR_PLLRDY)!=0);

  // select HSI48 as the USB clock source

  RCC->CFGR3 = (RCC->CFGR3 &~ RCC_CFGR3_USBSW) | RCC_CFGR3_USBSW_HSI48;

  // set flash latency = 1

  FLASH->ACR = (FLASH->ACR &~FLASH_ACR_LATENCY) | FLASH_Latency_1;

  // AHB

  RCC->CFGR = (RCC->CFGR &~ RCC_CFGR_HPRE) | RCC_CFGR_HPRE_DIV1;

  // HCLK source = HSI48

  RCC->CFGR = (RCC->CFGR &~ RCC_CFGR_SW) | RCC_CFGR_SW_HSI48;
  while((RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI48);

  // PCLK1

  RCC->CFGR = (RCC->CFGR &~ RCC_CFGR_PPRE) | RCC_CFGR_PPRE_DIV1;

  // enable clock recovery system from USB SOF frames

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CRS,ENABLE);

  // Before configuration, reset CRS registers to their default values

  RCC->APB1RSTR |= RCC_APB1RSTR_CRSRST;
  RCC->APB1RSTR &=~ RCC_APB1RSTR_CRSRST;

  // Configure Synchronization input */
  // Clear SYNCDIV[2:0], SYNCSRC[1:0] & SYNCSPOL bits */

  CRS->CFGR &= ~(CRS_CFGR_SYNCDIV | CRS_CFGR_SYNCSRC | CRS_CFGR_SYNCPOL);

  // Set the CRS_CFGR_SYNCDIV[2:0] bits according to Prescaler value
  // CRS->CFGR |= 0;

  // Set the SYNCSRC[1:0] bits according to Source value

  CRS->CFGR |= CRS_CFGR_SYNCSRC_1;

  // Set the SYNCSPOL bits according to Polarity value
  // CRS->CFGR |= 0;

  // Configure Frequency Error Measurement
  // Clear RELOAD[15:0] & FELIM[7:0] bits

  CRS->CFGR &= ~(CRS_CFGR_RELOAD | CRS_CFGR_FELIM);

  // Set the RELOAD[15:0] bits according to ReloadValue value

  CRS->CFGR |= 47999;     // (48MHz/1000) -1

  // Set the FELIM[7:0] bits according to ErrorLimitValue value

  CRS->CFGR |= (0x22 << 16);

  // Adjust HSI48 oscillator smooth trimming
  // Clear TRIM[5:0] bits

  CRS->CR &= ~CRS_CR_TRIM;

  // Set the TRIM[5:0] bits according to RCC_CRS_HSI48CalibrationValue value

  CRS->CR |= (0x20 << 8);

  // Enable Automatic trimming

  CRS->CR |= CRS_CR_AUTOTRIMEN;

  // Enable Frequency error counter

  CRS->CR |= CRS_CR_CEN;
}

With those modifications in place I was able to hack together a build for the ‘custom HID’ example and after a bit of gentle persuasion it actually worked. Here’s the device descriptor dump as reported by the ‘USBView’ Windows debugging utility:

Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x40 (64)
idVendor:           0x0483 (STMicroelectronics)
idProduct:          0x5750
bcdDevice:          0x0200
iManufacturer:        0x01
iProduct:             0x02
iSerialNumber:        0x03
bNumConfigurations:   0x01

When a USB device is inserted there is a flurry of very fast interrupt-driven data exchange between the host and the device as the host first queries for the device descriptor and then, based on what it receives, comes back with a sequence of further queries for the other standard descriptors. Only if all that goes well will the host accept the device and allow its descriptors to be queried in tools like ‘USBView’.

So now I know that everything on the board works. All the features have been tested and I can happily use it for development and testing on the F042 platform going forward.

Pages: 1 2 3 4 5 6 7 8 9 10 11

 


Top