-
Notifications
You must be signed in to change notification settings - Fork 34
Preempt USB interrupt to read bytes in usbtiny #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
This change uses the serial number stored in the t85 eeprom to number the device. This makes it easier to identify which part you're talking to once you have more of them since the numbers are sticky, and don't change when the devices are enumerated in a different order. The main difficulty is what to do when the numbers are not unique. For the case where the numbers are all the same (never updated), I numbered them the same as before (in the order enumerated). For the case where there are some duplicates, but not all, I incremented the duplicate numbers by 1000. This could be done differently of course, but this seems to do the job. |
|
At this point, I think the serial over dw is working ok. I've included the mods to the usbtiny device, an example that sends serial over dw, and a monitoring utility to view it. One thing to point out is that I've left the serial bit defined to 2 for easier debugging cycles as that avoids having to constantly change fuses. Also, a bit of hardware is required to use the power cycle option on usbmon: |
|
This looks really good. Getting usbtiny to handle both usb and target serial comms in parallel as it were is great. (Aside - nice solution to formatting assembler in C files.) How does it behave when the target comms does break multiple USB packets? For example if the target writes a couple of pages of text to the comms port, does the usb port disconnect? Presumably this is all on Linux? I don't suppose you've been able to test on cygwin on Windows? Re repeatable assignment of usbtiny devices - what do you think of identifying by eprom in the target itself? (The connection finding code already gets the dwire up and running for each potential device, it could easily pick up a byte of eprom at the same time.) The device command could have an eprom option adress:value. The BC327 will work well for small boards. What are you using it with? My project uses an attiny85 to drive a strip of 144 RGBW leds and an atmega328 driving an LCD, in both cases I'm pretty sure there's going to be too much current required unfortunately. (And there's the >=0.6v drop). -- Dave. |
|
Thanks for the comment, I hope it all comes in handy. After too many errors, the usb port does disconnect. The usbmon utility handles this by simply reconnecting. I did do this only on Linux, so I'm not sure how it would be different in Windows. I believe libusb works the same on both, although I used version 1.0 instead of the older version dwdebug uses, but I don't think that should make a difference. I think that storing a number in the eprom is great, and the little wire code already does that. In fact, I made a change in commit "use serial number descriptor to identify usbtiny device" to take advantage of that. Basically, it uses the serial number from the little wire device instead of the enumeration index. I also use them in usbmon in order to be able to repeatedly open the same device. I also included an option on usbmon to change the number (try usbmon -h to see the option summary). For some reason, changing the serial number only works when you do it first thing after power cycling the digispark. I'm not sure why, but the code is part of the little wire stuff. Of course, you only need to set the serial number once even if you later update the flash. I've been using the BC327 for bare microcontrollers and simple boards like the digisparks. Of course, a different part would be needed for more current. For a lot of current, the transistor can drive a relay. Are you concerned with driving the dw line both low and high? It seems that it could cause electrical problems when the debugger and the target have different power supplies. In my "uart use example" commit, I made the send code only ever drive the line low. Also, I think that it's also bad if both sides happen to drive the line in opposite directions due to communication problems. When I drive the line low only, and use the internal pullup resistor to drive it high, rates of 100K are good, perhaps 150K. With an external pullup resistor of 5K, the waveforms look much better. So, perhaps speeds could be much higher. You mentioned some graphics software a while ago, is that what you're doing with lcd panels? |
|
Sorry I wasn't clear - I meant to identify littlewire/digisparks not by their own eeprom, but by the eeprom of the target device - i.e. in the design for the target device I would reserve one byte to distinguish it from others and pass that on the device command. This wouldn't just be for digisparks, it would work with a mix of digisparks and usb uarts. Thus when updating a target it wouldn't matter which digispark or uart it was connected to. I haven't been working on this for a few weeks, but when I get back to working on the lcd controller I would like to explore your other approach - where the target remains in debug wire approach and issues a software interrupt to request functionality of the debugger. As long as the software interrupt instruction is at a known location, dwdebug can recognise it as a function request and do things like printing an area of flash, or of data memory, or it could update a register with a pending keypress or fill in a keyboard buffer. Yes, I have made some primitive graphics experiments. I'm pleased with the quality of anti-aliasing I'm getting, something I'm rather obsessed about. It's not all that fast, as it includes a 6 bit square root in the blend algorithm. Fortunately the mul instruction makes that a lot faster than it might be. When I get back to it I'll put it up on github. Cheers -- Dave. |
|
If what you mean by 6 bit square root is a 6 bit argument, you can use a lookup table: I believe on the gcc compiler, you can declare it as PROGMEM or such, and it gets loaded into the flash where you might be able to spare the 64 bytes. |
|
Ah no, it's a 12 bit to 6 bit square root. Sadly a table would need 4096 12 bit values. Here's my code: It loops 6 times. |
|
Ok, well I'm not familiar with this kind of square root function. I just automatically thought of lookup tables when you mentioned an arithmetic function being too slow. Sometimes I use a combination of a lookup table for some number of significant bits and an estimate for the rest. Or sometimes a base 2 log estimate is useful (position of msb is whole number part, the rest is the fraction), but that's mostly on intel processors since they have instructions for position of msb and for shift by n bits which is the inverse operation. But that's a whole different thing. |
|
Not completely stable, but getting there. |
|
By turning off and on the sync interrupt, the monitor gets more stable. I don't get disconnects anymore, but it could use some stress testing. |
|
DW should be open drain since it prevents the two sides from being able to drive the signal in opposite directions. And, it also allows for power supplies to have different voltages. The data sheet states that an external pull up resister is optional, and should be 10K to 20K if present. I'm using 10K since that makes for the best looking waveforms. It looks like faster baud rates should be possible. I made some changes to timing sensitive areas, and while I believe I got it right, my scope is only 1 MHz, so I didn't check all of the timings. I'll do that soon by slowing down the target for a test. The timing is affected since the rise times are longer now. |
|
It is possible for usbFunctionSetup to receive a valid setup This problem is not a regression, it also affects the master branch. |
|
The error rate is greatly reduced by including a short break as a preamble. This overcomes interrupt latency on the target. Long breaks are also detected. |
|
Allow the monitor to establish and reestablish connection without switching to dw mode. In fact, the monitor now works on any pin, and doesn't require dw at all, but is able to share the reset pin with dw when required. |
|
My original idea behind calculating dwBitTime in the interrupt routine is to make it possible to capture data immediately following sync pulses since I use this to differentiate between a target in dw mode vs using the software uart, and to speed things up. I couldn't resist trying out this change; however, I now think that it's worth using a hardware uart since the microcontrollers can't do both bitbanged serial and usb simultaneously. While it would be possible to speed up the lw device and avoid some lost data with double buffering, it wouldn't eliminate those problems. I thought that using a t4313 would be a better choice than the t85 since it has a hardware uart. While I may still try that, I've attached a t85 to my ft232 and talk to it via bitbanged i2c over the rs232 handshake lines. This is an interesting combination for a variety of applications since it combines a faster usb device with the uart unencumbered by the microcontroller with both free to do other jobs. My plan is to use the microcontroller to detect baud rates, provide gpio, and to use its eeprom to hold a serial number along with other calibration. I would be nice to use the same clock for both the ft232 and the microcontroller, but absent that, I can calibrate the relative speeds. Apparently the ft232 I'm using is a clone since the ftdi configuration utilities and drivers will not program it's eeprom, so I'm avoiding ft232 specific features. Another problem I've ran into is that io calls to the ft232 sporadically fail. I see this particularly with ioctls I imagine since I use those excessively. I've ordered other serial port parts to try in case I have a bad part. Have you had problems with bad ft232s? |
|
I haven't had problems with my cheap ft232's, but I haven't bashed them really hard. Rather than an ft232 and a t85, how about a pair of t85's? One to handle usb comms with the PC, and the other to handle DWire and software uart comms with the target? The usb comms t85 would run littlewire and communicate with the other over ISP. (Presumably an unmodified littlewire device would be sufficient.) |
|
Oops. s/ISP/SPI/ |
|
I think that two t85s would work better than one since the major bottleneck is running two async protocols simultaneously where each wants to be non-interruptable. An spi connection can be synchronous so it can be interrupted without any issue, but the native support on the t85 would require 3 wires, I believe. Perhaps a variation of i2c would be preferable since that would save one wire. My guess is that a t4313 would be able to do it all on one device since it has a hardware uart. However, all Attiny solutions require bit banged USB, which the ft232 does not. In general, I would prefer to do it all with one part which indicates a t4313. However, the ft232 runs USB at 12 MHz vs. the 1.5 MHz bit bang rate, and I think that rate difference comes in handy particularly on a loaded hub. Also, the ft232 should have a lower error rate on both USB and serial sides (but apparently not error free). At this point I'm experimenting with the ft232 + t85 combination (although it's looking like it'll fit in a t25). I have a couple of t4313s to experiment with, and may get to them eventually. |
|
Then there's the ATmega32u4. |
|
Here's my ft232 + t85 combination. |
This code is very preliminary, I'm only presenting this to ask if you might be interested in this idea. I hope you don't mind me toying with this stuff.
The basic aim is to make usbtiny responsive to the dw input by allowing the dw and usb interrupts to nest. The dw interrupt gets priority by being allowed to preempt the usb interrupt, but not vice versa. I made it so that it's possible to specify "wait for dWIRE line state change" and "Read bytes" simultaneously. The bytes are then read in the same interrupt as the one that receives the state change. I tried to maintain compatibility, and as far as I can tell dwdebug still works as before with these changes. I think the timing is still ok for the usb interrupt, but I haven't attempted to check that. Also, about 13 more bytes are used for the stack to nest interrupts, I'm not sure if that's ok.
My initial tests show that it does much better with reading from the dw line. It's not fast enough to always catch the first character, but that can be fixed by leading with a short break. The usb connection suffers, and will likely need to be reestablished on an ongoing basis to maintain the connection; however, I only enable the interrupt nesting when "wait for dWIRE line state change" is active to limit the extent of problems.
I made a separate utility that uses this new feature. I'll add it to the pull request once I get it to build without my personal environment. To simplify work on this, I made a define in main.c for the debug wire bit so that test cycles can be run without switching the wiring constantly. It's set to 2, but can be easily set back to 5.