USB HID

Please do not post requests
keru
Posts: 14
Joined: Fri Jun 26, 2015 4:39 pm

Re: USB HID

Post by keru » Fri Oct 30, 2015 1:51 am

thank you for the clarification, it all makes sense now :)

User avatar
ahull
Posts: 1650
Joined: Mon Apr 27, 2015 11:04 pm
Location: Sunny Scotland
Contact:

Re: USB HID

Post by ahull » Sat Oct 31, 2015 12:09 am

ahull wrote:
libarra wrote:
I think in one of the posts of this topic I included a sketch code which called Serial.begin() and Serial.end(), alternating them, each time the maple mini button was pressed and it did work for me (the maple mini was 'connected', 'disconnected', and 'connected' again), maybe it worked due to the delay between each button press.
That is interesting. I was using a non standard board (one of the oddball STM32F103R8T6 boards I bought on a whim a while back). I also thought there may be some sort of race condition going on. My other thought was that enumeration of the USB wasn't 100% reliable on that particular board anyway, so it was perfectly possible that it was nothing to do with my code.

I never actually got to the bottom of it. Real work got in the way, along with some other projects, for example converting an old pile of broken bits someone gave me, back in to this (the bits incidentally as well as being smashed, were white, so the fire engine red paint job, as well as looking good, hides a few plastic welds). I seem to have a reputation for fixing broken stuff, which has its plus points sometimes, however the food mixer was one of those "hmmm... I think I might just put that straight in the bin moments", until I googled Kenwood Chef and found there seems to be some almost religious fervour surrounding them.A reconditioned one goes for almost as much as a new one.

However I digress. The USB enumeration is something I intend to go back and experiment with some more, so give me a couple of days to get through the real work, and I will take another look.
Well, try as I might, I cannot get

Code: Select all

USBSerial serial_debug;
..

serial_debug.end()
.. wait for a while ..
serial_debug.begin()
... 
To do anything other than kill my USB serial connection.

With an FTDI adapter on the hardware serial port, I can see that the board knows I have disconnected. The below horrible mess of a sketch illustrates the issue. It spins in a loop, resets the usb serial after a few loops, again after a few more, then reboots the board and everything starts over.

Now the fact that resetting the board with a software reboot brings the USB port back up suggests that this is not a problem on the Linux end, but either a timing or setup problem on the board itself. Does anybody else have any thoughts on this?

Code: Select all

Starting Loop 1 serial_debug is connected
 Loop 2 serial_debug is connected
 Loop 3 serial_debug is connected
 Loop 4 serial_debug is connected
 Loop 5 serial_debug is connected
 Loop 6 serial_debug is connected
 Loop 7 serial_debug is connected
 Loop 8 serial_debug is connected
 Loop 9 serial_debug is NOT connected
 Loop 10 serial_debug is NOT connected
 Loop 11 serial_debug is NOT connected
 Loop 12 serial_debug is NOT connected
 Loop 13 serial_debug is NOT connected
 Loop 14 serial_debug is NOT connected
 Loop 15 serial_debug is NOT connected
 Loop 16 serial_debug is NOT connected
 Loop 17 serial_debug is NOT connected
 Loop 18 serial_debug is NOT connected
 Loop 19 serial_debug is NOT connected
 Loop 20 serial_debug is NOT connected
 Loop 21 serial_debug is NOT connected
 Loop 22 serial_debug is NOT connected
 Loop 23 serial_debug is NOT connected
 Loop 24 serial_debug is NOT connected
 Loop 25 serial_debug is NOT connected
 Loop 26 serial_debug is NOT connected
 Loop 27 serial_debug is NOT connected
 Loop 28 serial_debug is NOT connected�
Starting Loop 1 serial_debug is connected
 Loop 2 serial_debug is connected
 Loop 3 serial_debug is connected
 Loop 4 serial_debug is connected
 Loop 5 serial_debug is connected
 Loop 6 serial_debug is connected
 Loop 7 serial_debug is connected
 Loop 8 serial_debug is connected
 Loop 9
Output from FTDI serial port.

Code: Select all

// Was... STM32_PIR_Blink -  Simple Low Power demo using a PIR or other "button"
// Now, just a desparate attempt to get USB serial to disconnect and connect reliably. 

// Defined for power and sleep functions pwr.h and scb.h
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
#include <libmaple/usb.h>
// #include <libmaple/usb_serial.h>

int BOARD_LED_PIN = PB0;
int BOARD_BUTTON = PA0;
int DISPLAY_BUTTON = PA1;

volatile bool boardButtonInterruptFlag = false;
volatile bool displayButtonInterruptFlag = false;

// DEBUG: Remove USB serial if using low power
USBSerial serial_debug;


void boardButtonInterrupt() {
  boardButtonInterruptFlag = true;
}

void displayButtonInterrupt() {
  displayButtonInterruptFlag = true;
}


void setup() {
  Serial1.begin(9600);
  for (int i = 0; i < 4; i++)
  {
    pinMode(BOARD_LED_PIN, OUTPUT);
    digitalWrite(BOARD_LED_PIN, 0);
    toggleLED();
    delay(100);
    toggleLED();
    delay(100);
  }
  // Slow down to 8MHz (current drops to ~ 18mA
  //clockARM8();
  // disableClocks();

  delay(1000);
  pinMode(BOARD_BUTTON, INPUT);
  pinMode(DISPLAY_BUTTON, INPUT_PULLUP);

  attachInterrupt(BOARD_BUTTON, boardButtonInterrupt, CHANGE);

  attachInterrupt(DISPLAY_BUTTON, displayButtonInterrupt, CHANGE);
  Serial1.println();
  Serial1.print("Starting");
}

void loop() {
  int i = 0;
  while (true)
  {
    i++;
    toggleLED();
    Serial1.print(" Loop ");
    Serial1.print(i);
    serial_debug.println("Loop");
    delay(500);
    if ((i % 10) == 9 )
    {
      serial_debug.println("serial_debug.end()");
      serial_debug.end();
      delay(10000);
      resetUSB();
      serial_debug.begin();
      resetUSB();
      delay(10000);
      USBSerial serial_debug;

      serial_debug.begin();
      serial_debug.println("serial_debug.begin()");
    }
    if (serial_debug.isConnected()) {
      Serial1.println(" serial_debug is connected");
    } else {
      Serial1.println(" serial_debug is NOT connected");
    }
    if ((i % 29) == 28 )
    {
      systemHardReset();
    }

  }
  // WFI - current drops to ~12mA
  // sleepMode();
  standbyModeDeepsleep();
  //stopModeDeepsleep;
  if (boardButtonInterruptFlag)
  {
    //toggleLED();
    delay(10);
    //toggleLED();
    boardButtonInterruptFlag = false;
  }
  // Someone pressed or released a button... Do stuff... wake up the dog, photgraph the wild life, switch on the air raid siren.. or whatever.
  digitalWrite(BOARD_LED_PIN, (digitalRead(BOARD_BUTTON)));

  // toggleLED();


  if (displayButtonInterruptFlag)
  {
    //Someone Pressed the button on the display.
    systemHardReset();
  }
}

void toggleLED()
{
  digitalWrite(BOARD_LED_PIN, (!digitalRead(BOARD_LED_PIN)));
}

void clockARM8()
{
  // Switch to the 8MHz external clock. We loose USB, but we consume 2/3 less power.
  rcc_switch_sysclk(RCC_CLKSRC_HSE);
}

void disableClocks()
{
  // Disable all peripheral clocks except GPIOA, GPIOB and TIMER1
  rcc_clk_disable(RCC_ADC1);
  rcc_clk_disable(RCC_ADC2);
  rcc_clk_disable(RCC_ADC3);
  rcc_clk_disable(RCC_AFIO);
  rcc_clk_disable(RCC_BKP);
  rcc_clk_disable(RCC_CRC);
  rcc_clk_disable(RCC_DAC);
  rcc_clk_disable(RCC_DMA1);
  rcc_clk_disable(RCC_DMA2);
  rcc_clk_disable(RCC_FLITF);
  rcc_clk_disable(RCC_FSMC);
  //rcc_clk_disable(RCC_GPIOA);
  //rcc_clk_disable(RCC_GPIOB);
  rcc_clk_disable(RCC_GPIOC);
  rcc_clk_disable(RCC_GPIOD);
  rcc_clk_disable(RCC_GPIOE);
  rcc_clk_disable(RCC_GPIOF);
  rcc_clk_disable(RCC_GPIOG);
  rcc_clk_disable(RCC_I2C1);
  rcc_clk_disable(RCC_I2C2);
  rcc_clk_disable(RCC_PWR);
  rcc_clk_disable(RCC_SDIO);
  rcc_clk_disable(RCC_SPI1);
  rcc_clk_disable(RCC_SPI2);
  rcc_clk_disable(RCC_SPI3);
  rcc_clk_disable(RCC_SRAM);
  //rcc_clk_disable(RCC_TIMER1);
  rcc_clk_disable(RCC_TIMER2);
  rcc_clk_disable(RCC_TIMER3);
  rcc_clk_disable(RCC_TIMER4);
  rcc_clk_disable(RCC_TIMER5);
  rcc_clk_disable(RCC_TIMER6);
  rcc_clk_disable(RCC_TIMER7);
  rcc_clk_disable(RCC_TIMER8);
  rcc_clk_disable(RCC_TIMER9);
  rcc_clk_disable(RCC_TIMER10);
  rcc_clk_disable(RCC_TIMER11);
  rcc_clk_disable(RCC_TIMER12);
  rcc_clk_disable(RCC_TIMER13);
  rcc_clk_disable(RCC_TIMER14);
  rcc_clk_disable(RCC_USART1);
  rcc_clk_disable(RCC_USART2);
  rcc_clk_disable(RCC_USART3);
  rcc_clk_disable(RCC_UART4);
  rcc_clk_disable(RCC_UART5);
  rcc_clk_disable(RCC_USB);
}

void enableClocks()
{
  // Enable all peripheral clocks (except GPIOA, GPIOB and TIMER1 since we assume these were not disabled)
  //
  rcc_clk_enable(RCC_ADC1);
  rcc_clk_enable(RCC_ADC2);
  rcc_clk_enable(RCC_ADC3);
  rcc_clk_enable(RCC_AFIO);
  rcc_clk_enable(RCC_BKP);
  rcc_clk_enable(RCC_CRC);
  rcc_clk_enable(RCC_DAC);
  rcc_clk_enable(RCC_DMA1);
  rcc_clk_enable(RCC_DMA2);
  rcc_clk_enable(RCC_FLITF);
  rcc_clk_enable(RCC_FSMC);
  //rcc_clk_enable(RCC_GPIOA);
  //rcc_clk_enable(RCC_GPIOB);
  rcc_clk_enable(RCC_GPIOC);
  rcc_clk_enable(RCC_GPIOD);
  rcc_clk_enable(RCC_GPIOE);
  rcc_clk_enable(RCC_GPIOF);
  rcc_clk_enable(RCC_GPIOG);
  rcc_clk_enable(RCC_I2C1);
  rcc_clk_enable(RCC_I2C2);
  rcc_clk_enable(RCC_PWR);
  rcc_clk_enable(RCC_SDIO);
  rcc_clk_enable(RCC_SPI1);
  rcc_clk_enable(RCC_SPI2);
  rcc_clk_enable(RCC_SPI3);
  rcc_clk_enable(RCC_SRAM);
  //rcc_clk_enable(RCC_TIMER1);
  rcc_clk_enable(RCC_TIMER2);
  rcc_clk_enable(RCC_TIMER3);
  rcc_clk_enable(RCC_TIMER4);
  rcc_clk_enable(RCC_TIMER5);
  rcc_clk_enable(RCC_TIMER6);
  rcc_clk_enable(RCC_TIMER7);
  rcc_clk_enable(RCC_TIMER8);
  rcc_clk_enable(RCC_TIMER9);
  rcc_clk_enable(RCC_TIMER10);
  rcc_clk_enable(RCC_TIMER11);
  rcc_clk_enable(RCC_TIMER12);
  rcc_clk_enable(RCC_TIMER13);
  rcc_clk_enable(RCC_TIMER14);
  rcc_clk_enable(RCC_USART1);
  rcc_clk_enable(RCC_USART2);
  rcc_clk_enable(RCC_USART3);
  rcc_clk_enable(RCC_UART4);
  rcc_clk_enable(RCC_UART5);
  rcc_clk_enable(RCC_USB);
}


void systemHardReset(void) {
  // Perform a system reset, see ../libmaple/nvic.c for the method
  nvic_sys_reset();
  // We will never get any further than this.

}

void sleepMode()
{
  asm("   WFI");
}

void stopModeDeepsleep()
{
  // Clear PDDS and LPDS bits
  PWR_BASE->CR &= PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF;

  // System Control Register Bits. See...
  // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Cihhjgdh.html

  // Stop mode "PDDS and LPDS bits + SLEEPDEEP bit + WFI "
  // Low-power deepsleep bit.
  // PWR_BASE->CR |= PWR_CR_LPDS;

  // Set PDDS and LPDS bits for standby mode, and set Clear WUF flag (required per datasheet):
  PWR_BASE->CR |= PWR_CR_CWUF;   //
  PWR_BASE->CR |= PWR_CR_LPDS;
  PWR_BASE->CR |= PWR_CR_PDDS;
  // Enable wakeup pin bit.
  //PWR_BASE->CR |=  PWR_CSR_EWUP;
  PWR_BASE->CR |= PWR_CSR_EWUP;   // Enable PA0 wakeup pin

  // Set Power down deepsleep bit.
  // PWR_BASE->CR |= PWR_CR_PDDS;
  // Unset Low-power deepsleep.
  // PWR_BASE->CR &= ~PWR_CR_LPDS;

  // Set sleepdeep in the system control register - if set, we deepsleep and coldstart from RTC or pin interrupts.
  SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;
  // Now go into ARM halt mode, wake up on interrupt
  asm("    wfi");
}

void standbyModeDeepsleep()
{

  // Clear PDDS and LPDS bits
  PWR_BASE->CR &= PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF;

  // System Control Register Bits. See...
  // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Cihhjgdh.html

  // Stop mode "PDDS and LPDS bits + SLEEPDEEP bit + WFI "
  // Low-power deepsleep bit.
  // PWR_BASE->CR |= PWR_CR_LPDS;

  // Set PDDS and LPDS bits for standby mode, and set Clear WUF flag (required per datasheet):
  PWR_BASE->CR |= PWR_CR_CWUF;   //
  PWR_BASE->CR &= ~PWR_CR_LPDS;
  PWR_BASE->CR |= PWR_CR_PDDS;
  // Enable wakeup pin bit.
  //PWR_BASE->CR |=  PWR_CSR_EWUP;
  PWR_BASE->CR |= PWR_CSR_EWUP;   // Enable PA0 wakeup pin

  // Set Power down deepsleep bit.
  // PWR_BASE->CR |= PWR_CR_PDDS;
  // Unset Low-power deepsleep.
  // PWR_BASE->CR &= ~PWR_CR_LPDS;

  // Set sleepdeep in the system control register - if set, we deepsleep and coldstart from RTC or pin interrupts.
  SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;
  // Now go into ARM halt mode, wake up on interrupt
  asm("    wfi");
}

void resetUSB() {

  /*
    //Reset the USB interface on generic boards - developed by Victor PV
         gpio_set_mode(PIN_MAP[PA11].gpio_device, PIN_MAP[PA11].gpio_bit, GPIO_INPUT_FLOATING);
         //gpio_write_bit(PIN_MAP[PA11].gpio_device, PIN_MAP[PA11].gpio_bit,0);
         delay(30);
         gpio_set_mode(PIN_MAP[PA11].gpio_device, PIN_MAP[PA11].gpio_bit, GPIO_OUTPUT_PP);
         //for(volatile unsigned int i=0;i<256;i++);
         // Only small delay seems to be needed, and USB pins will get configured in Serial.begin
         //gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING);
         //gpio_set_mode(PIN_MAP[PA11].gpio_device, PIN_MAP[PA11].gpio_bit, GPIO_OUTPUT_PP);
  */

  //Reset the USB interface on generic boards - developed by Victor PV
  gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_OUTPUT_PP);
  gpio_write_bit(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, 0);
  delay(30);

  // for(volatile unsigned int i=0;i<256;i++);// Only small delay seems to be needed, and USB pins will get configured in Serial.begin
  gpio_set_mode(PIN_MAP[PA12].gpio_device, PIN_MAP[PA12].gpio_bit, GPIO_INPUT_FLOATING);
}


Scruffy, dirty sketch that demonstrates the issue.
- Andy Hull -

keru
Posts: 14
Joined: Fri Jun 26, 2015 4:39 pm

Re: USB HID

Post by keru » Sat Dec 05, 2015 4:10 am

I don't know if this can help or even if this is the right place, I'm sorry if it's not ... but I thought I would share since this thread got me interested in using the generic board as a keyboard.

Flabbergast here http://deskthority.net/workshop-f7/tmk- ... ml#p270371 made the TMK firmware work on a generic STM32F103 and the baide maple mini clone, using chibios. It's possible to keep the stm32duino's bootloader too.

User avatar
Luc_Exe
Posts: 37
Joined: Fri May 01, 2015 6:08 pm
Location: Viña del Mar, Chile

Re: USB HID

Post by Luc_Exe » Wed Jun 01, 2016 2:37 pm

The download in the original post saved my life.

I had to create a list of 500 1-wire iButtons (DS1990A), just selected the usb keyboard + mouse from the menu and paired it with the 1-wire library plus a little sketch to avoid all the hard work and common mistakes by wrong reading the small engraved key of each ibutton.

So, 2 hours coding and testing + 10 minutes to error-free read the 500 devices, instead of 10 hours doing it manually and probably with many errors.

niash
Posts: 1
Joined: Tue Aug 09, 2016 11:36 am

Re: USB HID

Post by niash » Tue Aug 09, 2016 11:50 am

Hello,
Thanks for all the effort for making Stm32duino & to "libarra" for bringing USB-HID to the stm32duino.
I am trying to make USB-RAW-HID with the libarra's fork. My findings as of now is that from MapleMini to PC is working fine whereas the other way doesnot happen. DataIn Endpoint 1 configured with Interrupt-Attributes & DataOut Endpoint 2 as Bulk-Attributes. RAW-HID report descriptors are same as defined in the usb_hid.c I am making effort looking other projects, understand & change in stm32duino. I shall update when I make some progress.
Any inputs?
Thanks.

User avatar
RogerClark
Posts: 7458
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: USB HID

Post by RogerClark » Tue Aug 09, 2016 9:39 pm

There is a branch of the repo where I integrated the various USB changes



https://github.com/rogerclarkmelbourne/ ... addMidiHID

I was hoping to merge this back into the master of the repo, but the problem is that if a user selects any USB device except Serial, they will not be able to upload withe the bootloader as there no way to reset the processor except via Serial ( at the moment)

Ideally we need a composite device that always has Serial, as well as whichever other devi es the user wants, but I am not an expert in USB and dont have time to write this myself

simonf
Posts: 180
Joined: Sun Jul 26, 2015 4:03 pm

Re: USB HID

Post by simonf » Tue Aug 09, 2016 11:41 pm

RogerClark wrote:
I was hoping to merge this back into the master of the repo, but the problem is that if a user selects any USB device except Serial, they will not be able to upload withe the bootloader as there no way to reset the processor except via Serial ( at the moment)
If you unplug / replug does it go into bootloader mode before the program starts?

User avatar
RogerClark
Posts: 7458
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: USB HID

Post by RogerClark » Tue Aug 09, 2016 11:44 pm

If you power cycle or press reset you get into the bootloader but most people don't want to bother doing that

User avatar
ahull
Posts: 1650
Joined: Mon Apr 27, 2015 11:04 pm
Location: Sunny Scotland
Contact:

Re: USB HID

Post by ahull » Wed Aug 10, 2016 7:40 am

This idea may have been suggested before, but would it be possible to re-enumerate the device in a manner similar to the Cypress CY7C68013A series 8051 based devices.

My understanding of the way these work, is that the enumerate as one device, this then updates the firmware, causing the device to re-enumerate as a different device. I'm not sure if this would be a workable solution in our case though, so your thoughts are welcome.
- Andy Hull -

cologne86
Posts: 16
Joined: Wed Jul 20, 2016 7:25 pm

Re: USB HID

Post by cologne86 » Fri Sep 16, 2016 2:17 am

hello,
at first thank you for your great work
i built a small joystick and the library works perfect for that.
I only have a question about PB10. It seems the internal pull-up ist working for serial, but not for the joystick.
Could that be? i seems weird to me :D I have no problem with the other 10 buttons.

i will try to use another pin, so it will probably not be a problem at all.

Post Reply