USB HID microbasic

Hallo,

Ik heb het voorbeeld uit de help functie van MicroBasic voor USB HID geprobeerd (zie hieronder).
In de uitleg hierover staat dat dit werkt onder 48MHz en op in het schema wordt een 8 MHz kristal gebruikt.

Mijn instellingen in WinPic zien jullie in bijlage. Ik gebruik een 20 MHz kristal. (De CPU frequentie is bij mij dan toch 48 MHz? (Hoewel ik niet goed snap dat die frequentie hoger kan zijn dan die van mijn kristal)).

Bij het insteken van de USB krijg ik de melding dat er problemen zijn met het USB apparaat.

Wat doe ik fout?

(Ik heb met de HID terminal van bij tools een descriptor file gemaakt en deze geïncludeerd in mijn programma.)

(Dit is de eerste keer dat ik USB HID in MikroBasic gebruik, ik heb met JAL wel succesvol USB RS232 emulatie gebruikt.)

code:


program USBtest

include USBdsc

dim k as byte
dim userRD_buffer as byte[64]
dim userWR_buffer as byte[64]

sub procedure interrupt
  asm
    CALL _Hid_InterruptProc
    nop
  end asm
end sub

sub procedure Init_Main
  ' Disable all interrupts
  ' Disable GIE, PEIE, TMR0IE, INT0IE,RBIE
  INTCON  = 0
  INTCON2 = $F5
  INTCON3 = $C0
  ' Disable Priority Levels on interrupts
  RCON.IPEN = 0
  PIE1 = 0
  PIE2 = 0
  PIR1 = 0
  PIR2 = 0

  ' Configure all ports with analog function as digital
  ADCON1 = ADCON1 or $0F

  ' Ports Configuration
  TRISA = 0
  TRISB = 0
  TRISC = $FF
  TRISD = $FF
  TRISE = $07

  LATA = 0
  LATB = 0
  LATC = 0
  LATD = 0
  LATE = 0

  ' Clear user RAM
  ' Banks [00 .. 07] ( 8 x 256 = 2048 Bytes )
  asm
    LFSR    FSR0, $000
    MOVLW   $08
    CLRF    POSTINC0, 0
    CPFSEQ  FSR0H, 0
    BRA     $ - 2
  end asm

  ' Timer 0
  T0CON = $07
  TMR0H = (65536 - 156) >> 8
  TMR0L = (65536 - 156) and $FF
  INTCON.T0IE  = 1            ' Enable T0IE
  T0CON.TMR0ON = 1
end sub


'** Main Program **

main:
  Init_Main()
  Hid_Enable(@userRD_buffer, @userWR_buffer)

  do
    for k = 0 to 255
      ' Prepare send buffer
      userWR_buffer[0] = k

      ' Send the number via USB
      Hid_Write(@userWR_buffer, 1)
    next k
  loop until FALSE

  Hid_Disable
end.

De PLL divider maakt 4MHz van de 20MHz, en de PLL maakt daar weer 48MHz van voor de USB.
Ikzelf gebruik zelden USB, maar het lijkt te kloppen. (of de descriptor helemaal goed is weet ik niet. Klein foutje is genoeg om de boel niet te laten werken)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com
hadv

Golden Member

Een report length van 1 is wel heel erg klein, het HID protocol kan max 64 bytes per report verzenden/ontvangen. Effectief is dat 63 omdat het eerste byte wordt gebruikt voor de report identificatie.

Laat ook usbdsc eens zien, want daar zijn dat soort spannende dingen in te zien. Fouten in de HID descriptor zijn de belangrijkste oorzaken bij het niet herkennen door Windows.

De fuses zien er in ieder geval goed uit.

Just find out what you like and let it kill you

Blijkbaar moeten het deze instellingen zijn, zo werkt het wel.

Wat wel nog een probleem is: hoe beëindig je de USB verbinding?
Wanneer ik dit beëindig in de pic met "HID_Disable", hangt de computer vast, kan ik de muis niet meer bewegen en reageert hij niet meer op toetsenbord, enige optie is dan stroom van computer uittrekken...
Idem wanneer ik de usb gewoon uittrek of stroom van pic afzet.

Nu sluit ik dan altijd de computer volledig af om het uit te trekken... Hoe moet dit wel?

hadv

Golden Member

In principe moet het OS vaststellen dat het USB HID device is losgekoppeld.

Wat er gebeurt hangt ook van af hoe je PC-client software is ingericht, heb je een afhandeling voor 'device unplugged'?

Wat je nog kunt proberen is dmv 'Safely Remove Hardware and Eject Media'.

Just find out what you like and let it kill you

Nee, ik heb daar geen afhandeling voor voorzien, denk ik, hoe doe ik dat concreet?
Voorlopig gebruik ik de HID terminal an de tools van MikroBasic. Maar kan dit liggen door een fout in dit programma? Je moet het normaal toch ook kunnen uittrekken als het programma niet actief is, en dat gaat nu ook niet.

Ik denk niet dat HID_disable() nodig is. (ik vermoed dat dan alle HID geblokkeerd raakt, waardoor ook muis en keyboard dood zijn)
De HID examples bij de compiler gebruiken HID_disable() ook niet.
Ontkoppelen van het USB device of beeindigen van de PC applicatie stoppen ook de HID connectie automatisch.

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Met deze instellingen werkt mijn LCD scherm (HD44780) niet meer... Met de instellingen van mijn eerste bericht werkt het LCD scherm wel, maar de USB niet. Hoe los ik dit op?

En wanneer ik de analoog-digitaal converter gebruik, werkt de USB ook niet meer.

Da's onzin...
Beiden hebben weinig met elkaar te maken, er zal wel een fout in je code zitten.

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Nochtans is het toch zo dat als ik, bij hetzelfde hex bestand, in WinPic enkel die instellingen verander ofwel enkel het LCD scherm ofwel enkel USB werkt...

Mijn code:

code:


program USBtest3

include "USBdsc"
include "tombleeser"

dim
 userWR_buffer  as  byte[64]
 userRD_buffer  as  byte[64]
dim adcvalue as byte

sub procedure interrupt
  HID_InterruptProc
end sub

main:

TRISA.0 = 1   'AN0
TRISA.1 = 1   'AN1
TRISA.2 = 1   'AN2 Vref-
TRISA.3 = 1   'AN3 Vref+
TRISA.5 = 1   'AN4
TRISE.0 = 1   'AN5
TRISE.1 = 1   'AN6
TRISE.2 = 1   'AN7
'TRISB.2 = 1   'AN8 (ook lcd)
'TRISB.3 = 1   'AN9 (ook lcd)

TRISA.4 = 1   'A4

TRISD.0 = 0   'output
TRISD.1 = 0   'output
TRISD.2 = 0   'output
TRISD.3 = 0   'output

TRISD.4 = 1   'input
TRISD.5 = 1   'input
TRISD.6 = 1   'input
TRISD.7 = 1   'input

TRISC.0 = 0
TRISC.7 = 0   'output groene led
TRISC.6 = 0   'output rode led

TRISB = 0                   ' PORTB is output
Lcd_Config(PORTB, 7, 6, 5, 4, PORTB, 2, 0, 3)
Lcd_Cmd(Lcd_CURSOR_OFF)     ' Turn off cursor
Lcd_Cmd(Lcd_Clear)
Lcd_Out(1, 1, "USB interface")
PORTC.0 = 1

  'interrupts uitschakelen:
	INTCON = 0                             ' Disable GIE, PEIE, TMR0IE,INT0IE,RBIE
	INTCON2 = 0xF5
	INTCON3 = 0xC0
	RCON.IPEN = 0                          ' Disable Priority Levels on interrupts
	PIE1 = 0
	PIE2 = 0
	PIR1 = 0
	PIR2 = 0


  HID_Enable(@userRD_buffer, @userWR_buffer)
  Delay_mS(1000)
  Delay_mS(1000)

  while true
        if HID_read() > 0 then
           'Lcd_Cmd(Lcd_Clear)
           LCD_byte_line_pos_dec(userRD_buffer[0], 2, 1, 3, 3)
           
           'adcvalue = adc_readtom(0, 0, 0) >> 2
           'LCD_byte_line_pos_dec(adcvalue, 2, 6, 3, 3)
           userWR_buffer[0] = 83
           HID_Write(@userWR_buffer, 1)
        end if
  wend
end.

[Bericht gewijzigd door elektronica op 8 juli 2017 22:44:53 (85%)]

Gevonden! PBADEN (=Port B ADC pins 0-4 enable) moet uitgeschakeld staan, want daar hangt het LCD scherm op aangesloten.

Nu werkt alleen de ADC (op de andere poorten) nog niet tegelijk met de USB...

De 18F4550 is een vrij antieke pic, je kunt daarbij niet de individuele A/D kanalen aan of uit zetten, alleen vanaf AN0 naar boven...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Voor het probleem met de ADC:

Met deze delen in de code werkt de usb verbinding wel:

code:


        ADCON1.VCFG0 = 0

        ADCON1.VCFG1 = 0

        ADCON0.CHS0 = 0
        ADCON0.CHS1 = 0
        ADCON0.CHS2 = 0
        ADCON0.CHS3 = 0

        ADCON0.ADON = 1

        Delay_us(22)

        ADCON0.GO = 1

        while ADCON0.GO = 1
        wend

Maar met dit in de code geeft windows reeds na het insteken van de usb stekker dat het usb apparaat niet herkend werd:

code:


       dim channel2 as byte    'bij declaraties
       dim Vrefneg2 as byte
       dim Vrefpos2 as byte

        channel2 = 0
        Vrefneg2 = 0
        Vrefpos2 = 0


        If Vrefpos2 = 0 then    'VERSCHIL
           ADCON1.VCFG0 = 0
        else
           ADCON1.VCFG0 = 1
        end if

        If Vrefneg2 = 0 then    'VERSCHIL
           ADCON1.VCFG1 = 0
        else
           ADCON1.VCFG1 = 1
        end if

        ADCON0.CHS0 = 0
        ADCON0.CHS1 = 0
        ADCON0.CHS2 = 0
        ADCON0.CHS3 = 0
        'ADCON0 = ADCON0 + (channel2 << 2)    'VERSCHIL

        ADCON0.ADON = 1

        Delay_us(22)

        ADCON0.GO = 1

        while ADCON0.GO = 1
        wend

(Deze laatste code had ik oorspronkelijk in een functie in mijn library staan en zou ik er terug willen inzetten)

Hoe verklaar je dit? Normaal zou dit toch geen verschil mogen geven? Hoe kan ik dit oplossen?

(Voor als jullie het volledige programma zouden willen zien:)

code:


program USBtest3

include "USBdsc"
include "tombleeser"

dim
 userWR_buffer  as  byte[64]
 userRD_buffer  as  byte[64]
dim adcval as word

dim channel2 as byte
dim Vrefneg2 as byte
dim Vrefpos2 as byte

sub procedure interrupt
  HID_InterruptProc
end sub

main:

TRISA.0 = 1   'AN0
TRISA.1 = 1   'AN1
TRISA.2 = 1   'AN2 Vref-
TRISA.3 = 1   'AN3 Vref+
TRISA.5 = 1   'AN4
TRISE.0 = 1   'AN5
TRISE.1 = 1   'AN6
TRISE.2 = 1   'AN7
'TRISB.2 = 1   'AN8 (ook lcd)
'TRISB.3 = 1   'AN9 (ook lcd)

TRISA.4 = 1   'A4

TRISD.0 = 0   'output
TRISD.1 = 0   'output
TRISD.2 = 0   'output
TRISD.3 = 0   'output

TRISD.4 = 1   'input
TRISD.5 = 1   'input
TRISD.6 = 1   'input
TRISD.7 = 1   'input

TRISC.0 = 0
TRISC.7 = 0   'output groene led
TRISC.6 = 0   'output rode led

TRISB = 0                   ' PORTB is output
Lcd_Config(PORTB, 7, 6, 5, 4, PORTB, 2, 0, 3)
Lcd_Cmd(Lcd_CURSOR_OFF)     ' Turn off cursor
Lcd_Cmd(Lcd_Clear)
Lcd_Out(1, 1, "USB interface")
PORTC.0 = 1

  'interrupts uitschakelen:
	INTCON = 0                             ' Disable GIE, PEIE, TMR0IE,INT0IE,RBIE
	INTCON2 = 0xF5
	INTCON3 = 0xC0
	RCON.IPEN = 0                          ' Disable Priority Levels on interrupts
	PIE1 = 0
	PIE2 = 0
	PIR1 = 0
	PIR2 = 0


  ADC_init(7)

  HID_Enable(@userRD_buffer, @userWR_buffer)
  Delay_mS(1000)
  Delay_mS(1000)

  while true
        if HID_read() > 0 then
           'Lcd_Cmd(Lcd_Clear)
           LCD_byte_line_pos_dec(userRD_buffer[0], 2, 1, 3, 3)
           
           'adc_readtomusb(0, 0, 0)
           
        channel2 = 0
        Vrefneg2 = 0
        Vrefpos2 = 0
        
        'If Vrefpos2 = 0 then
           ADCON1.VCFG0 = 0
        'else
           'ADCON1.VCFG0 = 1
        'end if

        'If Vrefneg2 = 0 then
           ADCON1.VCFG1 = 0
        'else
           'ADCON1.VCFG1 = 1
        'end if

        ADCON0.CHS0 = 0   ' kanaal0
        ADCON0.CHS1 = 0
        ADCON0.CHS2 = 0
        ADCON0.CHS3 = 0
        'ADCON0 = ADCON0 + (channel2 << 2)

        ADCON0.ADON = 1 'zet A/D module aan

        Delay_us(22)

        ADCON0.GO = 1 ' start conversie

        while ADCON0.GO = 1
        wend
           

           'LCD_byte_line_pos_dec(adcvalue, 2, 6, 3, 3)
           userWR_buffer[0] = 193
           userWR_buffer[1] = 194
           userWR_buffer[2] = 195
           userWR_buffer[3] = 196
           userWR_buffer[4] = 197
           userWR_buffer[5] = 198
           userWR_buffer[6] = ADRESH
           userWR_buffer[7] = ADRESL
           HID_Write(@userWR_buffer, 8)
        end if
  wend
end.

Wat ik het vreemdst van alles vind is dat dit reeds problemen geeft na het insteken van de usb stekker, dus wanneer de code die problemen geeft nog niet eens uitgevoerd is...

Dit probleem blijf ik eigenlijk hebben. Zonder ADC, maar door andere code toe te voegen die helemaal niets met usb te maken heeft, herkent hij het usb apparaat dikwijls ook niet meer.

Het enige gemeenschappelijke dat ik kan vinden is het gebruik van veel if-then structuren die de usb verbinding niet meer laten werken.

Ik denk dat ik dan een 2e pic (vb 16f1454) ga gebruiken om die enkel en alleen voor de usb verbinding in te laten staan, en die zijn data laten doorsturen/ontvangen via SPI met de "hoofd" pic

Ik denk dat ik dan een 2e pic (vb 16f1454) ga gebruiken om die enkel en alleen voor de usb verbinding in te laten staan

Da's natuurlijk zinloos; 1 pic moet dat makkelijk af kunnen. (met 2 wordt het nog lastiger door de chip-to-chip communicatie die er ook nog bij komt)
Of er problemen zijn hangt ook van de hoeveelheid data af. Je moet wel vaak genoeg de USB uitlezen om te voorkomen dat de boel vastloopt.
(a/d conversie is daarbij erg traag, dat houdt de boel nogal op. Je kunt ook een timerinterrupt gebruiken)

Er zou natuurlijk een fout in de USB library kunnen zitten; dit is tenslotte een oude compilerversie die allang niet meer ondersteunt wordt.
Als je toch 2 pics wilt gebruiken, is SPI niet de meest handige keuze. Waarschijnlijk werkt de UART een stuk makkelijker...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Wat Arco zegt!!! De USB moet elke 10mS uitgelezen worden, anders stopt de verbinding of komt helemaal niet op gang...

Domoticz en ESP8266, goede combo!!!

Over de USB om de 10 ms uit te lezen: ik gebruik

code:


sub procedure interrupt
  HID_InterruptProc
end sub

Dan is dit normaal toch in ieder geval in orde?

Ik kan er eigenlijk echt niet aan uit wat het probleem juist is waardoor het niet meer werkt. Als ik in een nieuw programma eerst de usb code invoeg en dan beetje bij beetje de andere code toevoeg, werkt het met code voor het GLCD, ram, menu's op lcd, ... Maar wanneer ik dan onderstaand blokje code invoeg op een plaats waarop het nog niet eens uitgevoerd wordt, dan wordt het usb apparaat niet meer herkend.

code:


      If PORTD.4 then
            Spi_Glcd_Write_Text("Uit", 85, 2, 1)
      else
            Spi_Glcd_Write_Text("Aan", 85, 2, 1)
      end if

(Keuze voor SPI chip-to-chip communicatie is omdat GLCD en SRAM reeds op SPI werkt.)

Ik bedoel het uitlezen met HID_Read(), dat moet zo vaak gebeuren dat de buffers niet vollopen.
(de interrupt haalt enkel de data binnen in een buffer, ik heb geen idee wat er gebeurt als die buffers overlopen...)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com