cnlohr / espusb

Software-only ESP8266 USB Device
Other
1.47k stars 230 forks source link

ESP32 as software defined USB host? #45

Closed bikeadventure closed 4 years ago

bikeadventure commented 6 years ago

Hi, great work you did (not only here)!

Is there a plan to not only make the ESP32 available as an USB device, but also connect USB devices (I am mostly interested in keyboards) to the ESP32?

Best regards from Germany

Peter

enricolam commented 6 years ago

I think there might be difficulties, as usb slaves only speak without thinking(send signal only), but the host listens and thinks( recieve and process). The thing is that the esp32 may not have enough processing power to do the job as a host.

However, this is just my concerns, the possibility is still to be determined.

best of luck Enrico

idesignstuff commented 6 years ago

The esp32 has two processors, so it seems much more possible than with an esp8266.

enricolam commented 6 years ago

I have to agree with you, not only processing power, but also esp32 have much more ram than atmega32u4( the most common chip with full usb function), but we still need work to determine it works or not. As the esp32 and 8266 does not support usb , it might require more power than other chips, like the atmega, to do the same job.

enricolam commented 6 years ago

I have to agree with you, not only processing power, but also esp32 have much more ram than atmega32u4( the most common chip with full usb function), but we still need work to determine it works or not. As the esp32 and 8266 does not support usb , it might require more power than other chips, like the atmega, to do the same job.

cnlohr commented 6 years ago

It would be relatively easy to do this on the ESP32 with low-speed, but, I made a serious effort to try it using high-speed USB and failed. I haven't had the heart to go back and make the ESP32 do low-speed USB which should be relatively easy to do.

4ndrej commented 6 years ago

Even low speed USB (USB-1's 12 Mbit/s = 1.5MB/s) should be fast enough for decent B/W printing when print jobs are under 200kB per page.

bikeadventure commented 6 years ago

And keyboards please :-)

cnlohr commented 6 years ago

Youuu guuyyyssssss. Tell you what. If $1,000 somehow appears in the next couple weeks earmarked for doing this on the '32, low-speed will get done.

bikeadventure commented 6 years ago

The guys from Espressif should be happy to extend the functionality at such a low price. For me as a tinkerer it is too hefty ;-)

cnlohr commented 6 years ago

I meant it as a joke but would still stand behind it.

bikeadventure commented 6 years ago

I understood it as half-joke, which it was ;-) And hope that Espressif reads and considers...

ReleaseBug commented 6 years ago

@cnlohr Hi there! I have seen you made a serious effort to try it using high-speed USB and failed. I noticed that low-speed USB based on voltage transmission mode , but high-speed USB based on current transmission mode. Voltage may be worked good with ESP8266's gpio.. but cuirrent ? I don't know how... I am a beginer and not assure does it have some help for you.

Last, thx your great project!

cnlohr commented 6 years ago

I was going after full-speed, not high-speed. High-speed might be possible, but would be very, very difficult. Full-speed SHOULD be fine, but I just ran into too many latency issues within the design of how the ESP32 is plumbed internally between the core and the AHB. I REALLY wish they had some mechanism to use internal system registers to IO pins but Espressif has confirmed no such plumbing exists :(.

tommeyers commented 6 years ago

Regarding

1) support for keyboards on esp32 - Can you use a BT keyboard like for Android? Or android tablet/phone via BT so you have a display and a keyboard? I use a WiFi access point on my ESP32 projects with a web page then interact with my browser.

2) For HD - Can you use WiFi to NAS drive? Or an API maybe using node-red to fetch/write data. Or MQTT.

The more I think about this the more I think that you may need to step back and define the problem you are trying to solve.

Tom Meyers

cnlohr commented 6 years ago

This really only applies to full-speed. As I think low speed wouldn't be that bad. The one thing I still don't know is if devices intended for high speed use, i.e. USB drives are fully accessible in full-speed mode.

Uuugghhhh I think I just figured out how to do this... Like the host-mode thing. It would require dedicated use of a I2S engine, and would need the APLL :-/ but other than that, it "should" work. Man, now I'm really jonesing for a Logic 8 Pro.

The idea is you could use the I2S engine to TX at exactly 12 MBits/s (using the APLL) then immediately flip it back over to sample at 32 MHz (needs to be at least baud * 2 + a little bit) then do some of the tricks I outlined in my Ethernet with the ESP8266 thing.

sbuller commented 6 years ago

Have you looked at the DSLogic Plus? I can't claim to have used either it or the Logic 8 Pro, but the DSLogic looks to be pretty comparable.

cnlohr commented 6 years ago

I just reallllyyyy love the Saleae USB protocol analysis

djhardrich commented 6 years ago

I’d highly recommend getting one of the cheap 8ch logic analyzers and using Pulseview (open-source, based on sigrok). Its protocol analysis is pretty awesome, and handles USB with filters ;) Feel free to drop me a message if I can help somehow, I could really use USB MIDI for a ton of projects!

EDIT: This isn’t to take away from Saleae, as they make an awesome product, it’s awfully crappy that they had to discontinue the cheapest model (and the reasons why are upsetting, to say the least).....

cnlohr commented 6 years ago

@djhardrich why not just interface the MIDI directly to the UART outputs? Or, for something like MIDI, you could do up to 8 simultaneous channels with the I2S engine in parallel mode...

djhardrich commented 6 years ago

@cnlohr That works really well for midi via DIN/3.5mm jack, but I’m in the position of porting a bunch of class compliant USB midi stuff from the stm32 to the esp32 (better flash security, more ram, BT, faster clock speed) and the USB transport is necessary for iOS/Android support without an extra usb->din midi adapter that most people don’t have..... Unless I’m missing something obvious/not-so-obvious?? EDIT: Also only really need 1 channel in/out for pretty much all of these projects, if that helps...

brainstorm commented 6 years ago

Subscribers on this issue, here's your opportunity to raise some money to get this done:

https://www.bountysource.com/issues/60310751-esp32-as-software-defined-usb-host

bikeadventure commented 6 years ago

cnlohr wrote on July 4th: Youuu guuyyyssssss. Tell you what. If $1,000 somehow appears in the next couple weeks earmarked for doing this on the '32, low-speed will get done.

brainstorm today started bountysource with 25 bucks, I added 50. So if some 30 to 40 other guys put something in that pot the crowd pays cnlohr to fulfil :-)

Spritetm commented 6 years ago

@cnlohr As a representative of Espressif, I think we can spot you that $1000USD. We'd pledge on the Bountysource site but as far as I can see they take 10% if you actually want to have the money... you can also contact me directly (jeroen at espressif period com) and we can skip that bit.

bikeadventure commented 6 years ago

GREAT! Making your solutions even better by paying the best brains in the crowd. You are my heroes of today ;-)

cnlohr commented 6 years ago

This is a very interesting turn of events considering the last few days... I should know more about my availability for this on Thursday...

Crypter commented 6 years ago

@cnlohr, which Thursday? We are all loosing our minds here! :D

chibiconsulting commented 6 years ago

@cnlohr, would/could low speed USB work on any GPIO pins? I use the I2C and I2S pins already so being able to use other pins would be a plus.

cnlohr commented 6 years ago

Sorry to keep everyone in the dark! But, my schedule is finally starting to open up. I should be able to take a first pass at this this coming weekend.

My primary goal is to go-for-the-gold FIRST. That means full-speed USB host. A word of warning is that this approach will not work as a full-speed USB-device because of the turn-around restriction on USB requiring clients to reply within 6.5 bit cycles of the last bit from the host. I can't figure out a way to do this on the ESP32, no matter what I try.

My backup will be to make a much more naieve system that does low-speed USB host, but that is sad and I don't want to go there unless I have to.

The way I am approaching it, I should be able to use the internal matrix, which should permit arbitrary pin usage. It would be limited to the first 32 IO pins. My intent is to use the I2S engine to output USB datagrams. Batch up most of a packet, then tack on the last few bits as another packet. When the first packet is done and an I2S interrupt is called, spinlock on the second one until the DMA is free then immediately switch the I2S around to be an input.

This has a side effect of being unable to use the dead-time bandwidth.

The I2S engine would need to operate at 25-30 MHz @ 16 bits wide despite only using two bits (Which is absolutely can!) Though this is embarrassingly wasteful bandwidth-wise, since the I2S engine doesn't support any 8-bit modes AFAIK.

The reason for operating at 25-30 instead of 12 is so I can do a trick similar to what I did with Espthernet where you can perform tricks with a LUT and clock recovery. If you lock to exactly 12 or exactly 24 MHz, the phase must remain precisely locked, if you are even slightly more than 2x the sample rate you can do some minimal recovery. Though with USB it will be tricky, considering the complicated bit stuffing rules... I think it should be algorithmically reasonable.

Unrelated: I did buy a saleae so I'll be going into this with the right tools.

Charles

brainstorm commented 6 years ago

Excellent! While you are at it, would it be possible to reuse https://github.com/xobs/grainuum/issues/2 as you explored a while ago? Having shared USB stacks could be beneficial in terms of portability while experimenting with different MCUs (as a developer)... although I understand that would be like going for gold++, so I'll keep my expectations low in that matter since what you are attempting is already awesome ;)

Spritetm commented 6 years ago

From what I remember, one of the I2S peripherals does actually have an 8-bit mode: while the chip was designed, I also complained that 16-bits are a bit wasteful in parallel mode and they added one in... will look up how to get that when I'm at work, it's been a while.

Edit: This is what I dug up. I don't know if it ever made it into the TRM, should look at that. Take care that the order of bytes within a word is kind-of strange (middle-endian?) so the bytes in memory might not come out in the order you expect.

Note: 1.you should use i2s1 module not i2s0, 2.the output data bits are I2S1O_DATA_OUT[7:0], (only 8bits mode is bit7~0,other mode not change )

  1. the data in buffer,you should exchange the position of bety01 and bety23 4.set I2S_TX_FIFO_MOD_FORCE_EN =1 tx_chan_mod = 1; tx_fifo_mod = 1; I2S_LCD_TX_WRX2_EN_S =1; I2S_LCD_TX_SDX2_EN_S =0;
cnlohr commented 6 years ago

@Spritetm I spent hours poking around at i2s0 seeing if I could find much useful hidden stuff... I never considered the possibility that I2S1 might be different than 2. Thank you!

@brainstorm grainuum is really for device-side stuff. This thread is specifically host-side stuff for the '32.

Spritetm commented 6 years ago

@cnlohr You can actually also use I2S0 for byte-wide access with a hack, if you want to: iirc the DMA addresses don't have to start at a word boundary, so you can 'interleave' 2 8-bit buffers into 1 16-bit buffer. Note I never tried that yet, but at the time the digital time didn't see a reason why it wouldn't work.

cnlohr commented 6 years ago

Wait... what? my throw-junk-at-the-wall-to-see-what-sticks game has definitely been lacking.

I am having a hard time imagining what that code would look like though.

@Spritetm The one other thing I wanted to ping you on was I was wondering if there was any way to initialize IO transfers and continue execution. I think I asked a while ago, but figured I'd ask again. As of right now, if you try to read stuff from the AHB? (the IO) it takes many processor cycles (more when running at higher speed). Is there any way to initialize the transfer and continue code execution then read later, or some mapping to the system registers that could permit it? Or is really, the only way forward for full-speed to use I2S with DMA?

Spritetm commented 6 years ago

@cnlohr What code? The 2-interleaved-8-bit-buffer thing? You essentially have a memory layout of (per byte) a1 b2 a2 b2 a3 b3 a4 b4 etc. You configure I2S to output 16 bits, but don't connect the top 8 to anything. If you want to output A, you set up a DMA buffer that starts at 0; if you want to output B you set up a buffer that starts at 1.

Wrt speed: I think what you're running into is 1. the fact that the peripherals only run at 80MHz and 2. you may be accessing the I2S peripheral over the AHB bus. 1 can't really be helped in any way... for 2, make sure you access it through 0x3ff4F000 (if you don't already), that should be faster. (Note that that address range does speculative reads... probably not an issue with I2S how you use it, but it's known to be an issue with FIFOs etc.) If you do a read in C, by the way, it can take a while because the registers normally are declared volatile and the C compiler will insert a memory barrier (MEMW).

Wrt continuing execution... In theory, you can make use of the load/store unit of the Xtensa... if you follow the read from the I2S by a bunch of instructions that do not depend on the result of the read, the core may be able to partially execute those; if anything, it probably helps because less pipeline bubbles.

cnlohr commented 6 years ago

@Spritetm A few notes/questions:

(1) I am running into other oddities with I2S0 vs 1... you mentioned that 0 should be able to do most of the same things, but, it's just odd... Does your statement before about only doing this on 1 still apply?

(2) I can't seem to find my old IO tests, but theoretically, should I be able to also read IO ports via 0x3ff44000 and not use the result of the previous read? I thought I tried that and found that all reads halted the core, it was just writes that could stack. I don't have an old binary, but, if the base of "GPIO" hasn't changed, then I will be very confused by it. That did not use the memw instruction, unless the assembler inserted it, or I may have made a mistake.

https://github.com/cnlohr/esp32-cnlohr-demo/blob/master/main/asm_test.S

(3) I would prefer to do a gpio-only solution despite it using more CPU because it lets you have a really sharp edge on the start of the transfer, for I2S I am not sure how to get a quick turnaround on interrupts so I can time switching the data-direction on the IO ports as well as hooking them up to the I2S inputs. A long time ago, someone mentioned

Spritetm commented 6 years ago

Erm, I think you accidentally pressed send too quickly...

Wrt 1, my emails are somewhat old and they perhaps have changed that in the final ESP32 silicon, but for all I know the byte access can only be done on one I2S peripheral. If you have some questions you want to ask the digital team that shouldn't take them too long to answer (they're in the middle of verifying the next chip....) I can forward that.

Wrt 2: I'm not exactly sure what you mean there... the trick is that the Xtensa has a load/store unit, and the APB bus has some storage for writes as well. If you do a write, that will get stored in the load/store unit or the APB bus buffer and the CPU can happily continue on its merry way, until either a memw is executed (which forces flushing the load/store unit or the buffer) or too many writes are queued.

If the Xtensa runs into a read instruction, this also goes to the load/store unit. The Xtensa will still try to continue execution for a bit, though, but can only do this for instructions where it does not need the result of the read. So if you have something like l32i a2, gpio_input; addi a3, a3, 1; addi a4, a5, 123; addi a3, a2,1, chances are that the three first instructions get executed at the full 240MHz but the last instruction takes longer as the Xtensa needs to wait for the read of the 1st instruction to succeed.

classic-gentleman commented 5 years ago

@cnolohr I have 8 bit parallel writes working fully. Check https://github.com/espressif/esp-iot-solution/issues/19 and if you have any further questions just shoot!

(And yes, considering little endian you must swap the pair of 16-bit "words" in a 32-bit "dword" and then swap the pair of bytes in the words. For me this is like the number one reason for pitching adding a permutation instruction to a future ESPxx, but of course this is solving the wrong problem; an actual parallel bus peripheral is the solution we're seeking.)

Uzlopak commented 5 years ago

@cnlohr Will you make it compatible with the latest sdk? Or will it be still stuck in the old sdk?

cnlohr commented 5 years ago

I am sorry this keeps getting pushed back. Some of it has to do with an anxiety regarding my confidence in the solution, and some of it has to do with being so inundated at work. If I ever do get any inspiration it will rise up on the list, but there's no shining beacon of "this will work!!" right now.

jaygarcia commented 5 years ago

@cnlohr thank you for all the time and energy you have put into this!

Matheus-Garbelini commented 5 years ago

@cnlohr off topic, but you may like to read this: ESP32/8266 Wi-Fi hacked Also thanks for all your work with USB.

eabase commented 5 years ago

@cnlohr What is the status of this? I think this is an exciting prospect and it would be a shame if it died on the finish line.

tobozo commented 5 years ago

doesn't ESP32-S2 solves this ?

eabase commented 5 years ago

As Ian42 says:

Whole some of those features are great, loosing bluetooth and the 2nd core is a show stopper for a lot of things..

If you are doing wifi stuff the 2nd core is great – as the wifi runs on that core and you can get your program running doing pretty close to real time stuff on the other core.. If you try and do real time stuff on a 8266, at the same time as wifi, it doesn’t work very well..

This this is more a esp32 lite, or a 8266 pro, as it sits somewhere between the esp8266 and the esp32. SO I thik their naming choice isn’t a good one…

So it's not clear at all how to use this on a standard ESP32.

cnlohr commented 4 years ago

Correct - that would take some work. But I am not going to address it. I burned out on trying to make full-speed comms work.

StuartRothrock commented 4 years ago

I have been using the April Brother Cactus WHID (esp12+32u4) on a few projects and like the functionality but it seems a bit dated for 2020, especially the 32u4 with 16kb mem and 8Mhz clock. Has anyone seen a product in the same USB stick format that provides the same USB host functionality? The serial interface as the only communication between the two processors is less than desired.

EUA commented 4 years ago

I know I late on this but has 2 cent. I programmed ESP32 Logic Analyzer with I2S & DMA and can capture up to 20Msps. Frequencies above 20MHz do not work in I2S mode. So if anyone try to do implement Full Speed USB stack, he need switch to 12Mhz if planing to use I2S.

RoganDawes commented 4 years ago

I have been using the April Brother Cactus WHID (esp12+32u4) on a few projects and like the functionality but it seems a bit dated for 2020, especially the 32u4 with 16kb mem and 8Mhz clock. Has anyone seen a product in the same USB stick format that provides the same USB host functionality? The serial interface as the only communication between the two processors is less than desired.

The WHID does not implement USB Host, it is a USB device only. A possible option that uses 802.15.4 for wireless comms is the nRF52840, available in a USB dongle format from a variety of suppliers.

sdima1357 commented 3 years ago

esp32 usb-ls soft host https://github.com/sdima1357/esp32_usb_soft_host