To do:
*I2C sniffer
*terminal text review and protocol documentation
*PIC extensions to raw2wire
*flashrom followup
Eventually I2C clock stretching
Pic extensions are already in the pic library and should be supporting pic10-18. The pic library is commented out due to space constraints. (working on the space thing)
Yup, I think just the <=16F need to be integrated with the others that I already have in there for the 18F and 24F.
You mean the binmode or raw2wire?
I added 18F and 24F extensions to raw2wire already. Just the others need to be added now.
I'm going to make a test SPI sniffer update that is triggered by low CS for pete to test. I also plan to add a bit-order shifting function so the hardware libraries can be LSB too (thanks for the demo!).
Here's some fancy (18F) ASM ways to flip bits. I checked the datasheet and it doesn't look like the 24F has a native function or anything.
http://www.piclist.com/techref/microchi ... evbits.htm (http://www.piclist.com/techref/microchip/math/bit/revbits.htm)
Added the bitorder adjustment and enabled in SPI. Your demo should be easier now :)
Going to look at SPI sniffer some more.
I guess speed isn;t very relevant here (buspirate) so a simple shift and or would do the trick. It wonders me why it wasn't in implemented in HW (at least into the spi logicsystem)
I did this, don't know if it's shorter than 8 if |= statements.
unsigned char bpRevByte(unsigned char c){
unsigned char r=0, i;
for(i=0b1; i!=0; i=i<<1){
if(c&i)r|=0b1;
r=r<<1;
}
return r;
}
[quote author="ian"]
unsigned char bpRevByte(unsigned char c){
unsigned char r=0, i;
for(i=0b1; i!=0; i=i<<1){
if(c&i)r|=0b1;
r=r<<1;
}
return r;
}
[/quote]
shouldn't it be for(i=0x80; i; i=i>>1) ? now you are shifting both bytes to the left. (first thinking!)
BTW r<<=1; is also valid. Dunno if it is quicker/shorter but mostly it is.
abc
if(c)r=c
r=r<<1 (c0)
if(b)r=cb
r=r<<1(cb0)
if(a)r=cba
The << should be at the top of the loop?
The code as currently check into SVN does not show a terminal when compiled on my pc. I didn't change the terminal code, so I assume it's a space or other compiler issue. There's nothing int he bootloader export region. I'll start rolling things back till it works tomorrow.
We should also get rid of the lsb/msb loops in bitbang and just reverse the byte when needed. Those are messy, and it could save some space.
base.h is set for v1a, long day...
get some sleep then!
I think msb/lsb should be done into procmenu.c to save even more bytes ;)
Ut moin!
The hardware CS on the spi sniffer seems to work well in my tests. I sent it to Pete for serious testing. If it shows a big improvement for him, then I'll try to integrate HW CS into the list of options. It only works with CS low (or no CS), CS high would require combining the SW and HW functions, which is a nightmare I'm not looking forward too :)
Now I'm going to test and tease out the bit order configuration to procmenu.c and get rid of bit order in the BBIO library.
I also plan to have a look at the new I2C sniffer today, and debug the STK500v2 clone firmware, there's been bug reports.
HiZ> |0b1
0x80 = 128 = 0b10000000
HiZ> |0b10101010
0x55 = 85 = 0b01010101
HiZ>
The bit reverse function seems ok. I added (temporary?) command | to convert bit order. I allow in Hi-Z because it's not a hardware function and it uses the converter, but I still think it's ugly and inconsistent to allow configuration in HiZ, and gives the user the impression that the configuration will stick between modes...
I need to update the PIC programming commands to use the new LSB technique, but everything else should be ok. I did not add LSB config to the binary modes that didn't have it already.
How would you ideally overhaul binmode?
I would do the reverse bitorder in the read/write functions:
in pseudocode: if(modeConfig.lsb) write(c) else write(reverse(c))
In binmode the script needs to do it IMHO :D
yup, sorry, that's what I did :) I moved all the stuff out of individual libraries and into procmenu.c. I'm testing now.
Sorry I need to read before post :$
It looks like the LSB/MSB status was inconsistent in the info screen/commands/help/wiki. I updated everything to reflect the help screen l/L msb/LSB.
SPI> [3 0 r:3]
CS ENABLED
WRITE: 0x03
WRITE: 0x00
READ: 0x03 0x02 0x01
CS DISABLED
SPI> L
MSB set: LEAST sig bit first
SPI> i
Bus Pirate v3a
Firmware v5.3RC (r428) Bootloader v4.3
DEVID:0x0447 REVID:0x3043 (B5)
http://dangerousprototypes.com
CFG1:0xF9DF CFG2:0x3F7F
*----------*
Pinstates:
1.(BR) 2.(RD) 3.(OR) 4.(YW) 5.(GN) 6.(BL) 7.(PU) 8.(GR) 9.(WT) 0.(Blk)
GND 3.3V 5.0V ADC VPU AUX CLK MOSI CS MISO
P P P I I I O O O I
GND 3.35V 5.01V 0.00V 0.00V L L H H L
POWER SUPPLIES ON
a/A/@ controls AUX pin
Normal outputs (H=3.3v, L=GND)
Pull-up resistors OFF
MSB set: LEAST sig bit first
*----------*
SPI> |3
0xC0 = 192 = 0b11000000
SPI> [192 0 r:3]
CS ENABLED
WRITE: 0xC0
WRITE: 0x00
READ: 0xC0 0x40 0x80
CS DISABLED
SPI> |0xc0
0x03 = 3 = 0b00000011
SPI>
Looks good in SPI and raw3wire with a 25AA EEPROM.
Here's my first take on porting the I2C sniffer to replace the old one. It doesn't use the byte request method of the old one, but it uses the ring buffer. We should look at triggers later, or at least use the 'r' to reset scheme of the SPI sniffer.
http://dangerousprototypes.com/forum/in ... 04#msg5804 (http://dangerousprototypes.com/forum/index.php?topic=617.msg5804#msg5804)
void I2C_Sniffer(unsigned char termMode)
{
unsigned char SDANew,SDAOld;
unsigned char SCLNew,SCLOld;
unsigned char DataState=0;
unsigned char DataBits=0;
unsigned char dat=0;
//unsigned char *BitBuffer=bpConfig.terminalInput;
//unsigned short BufferPos=0;
//unsigned short AckPos=0;
//unsigned short DataPos=0;
SDA_TRIS=1; // -- Ensure pins are in high impedance mode --
SCL_TRIS=1;
SCL=0; // writes to the PORTs write to the LATCH
SDA=0;
CNEN2bits.CN21IE=1; // enable change notice on SCL and SDA
CNEN2bits.CN22IE=1;
IFS1bits.CNIF=0; // clear the change interrupt flag
SDAOld=SDANew=SDA;
SCLOld=SDANew=SCL;
//while(!U1STAbits.URXDA&&(BufferPos<32768)) // BitBuffer Space = 4096*8 bits
while(1)
{
//user IO service
UARTbufService();
if(U1STAbits.URXDA == 1){//any key pressed, exit
c=U1RXREG;
break;
}
if(!IFS1bits.CNIF)continue; //check change notice interrupt
IFS1bits.CNIF=0;//clear interrupt flag
SDANew=SDA; //store current state right away
SCLNew=SCL;
if(DataState&&!SCLOld&&SCLNew) // Sample When SCL Goes Low To High
{
if(DataBits<8) //we're still collecting data bits
{
if(SDANew)
{
//BitBuffer[DataPos>>3]|=(0b10000000>>(DataPos&7)); // Store A One
dat|=1;
}
//else
//{
//BitBuffer[DataPos>>3]&=~(0b10000000>>(DataPos&7)); // Store A Zero
//}
dat=dat<<1;
//DataPos++;
DataBits++;
}
else
{
//put the data byte in the terminal or binary output
if(termMode){//output for the terminal
bpWhexBuf(dat);
}else{ //output for binary mode
UARTbuf(ESCAPE_CHAR); //escape character
UARTbuf(dat); //write byte value
}
if(SDANew) // SDA High Means NACK
{
//BitBuffer[AckPos>>3]&=~(0b11000000>>(AckPos&7)); // Store 00
UARTbuf('-');
}
else // SDA Low Means ACK
{
//BitBuffer[AckPos>>3]&=~(0b11000000>>(AckPos&7)); // Store 01
//BitBuffer[AckPos>>3]|=(0b01000000>>(AckPos&7));
UARTbuf('+'); //write ACK status
}
DataBits=0; // Ready For Next Data Byte
//BufferPos=DataPos; // Captured A Full Byte So Can Move Buffer On Now
//AckPos=BufferPos;
//DataPos=AckPos+2;
}
}
else if(SCLOld&&SCLNew) // SCL High, Must Be Data Transition
{
if(SDAOld&&!SDANew) // Start Condition (High To Low)
{
DataState=1; // Allow Data Collection
DataBits=0;
//BitBuffer[BufferPos>>3]&=~(0b11000000>>(BufferPos&7)); // Store 10 (Start)
//BitBuffer[BufferPos>>3]|=(0b10000000>>(BufferPos&7));
UARTbuf('[');//say start, use bus pirate syntax to display data
//BufferPos=BufferPos+2; // Move The Buffer On 2 Bits
//AckPos=BufferPos; // Set Ack And Data Postions In Buffer, Ready For A Byte
//DataPos=AckPos+2;
}
else if(!SDAOld&&SDANew) // Stop Condition (Low To High)
{
DataState=0; // Don't Allow Data Collection
DataBits=0;
//BitBuffer[BufferPos>>3]|=(0b11000000>>(BufferPos&7)); // Store 11 (Stop)
UARTbuf(']');//say stop
//BufferPos=BufferPos+2; // Move The Buffer On 2 Bits
}
}
SDAOld=SDANew; // Save Last States
SCLOld=SCLNew;
}
CNEN2bits.CN21IE=0; // Clear Change Notice
CNEN2bits.CN22IE=0;
//UART1RX(); // Wait For Some Input Before Transmitting Buffer, Even If Buffer Is Full
//I2C_Sniffer_Report(termMode,BufferPos);
if(termMode)
{
bpBR;
}
}
Speaking of SPI sniffer, the HW CS solution is certainly preferable. It has a 120ns timing requirement compared to ~50us (yes, us) requirement for the software version :)
Did a few fixes and a test. It works better than the old one, but still doesn't work at the Bus Pirate's '400' khz setting. 100khz works fine, which I think is an improvement over the previous version (manual says 70khz).
I'm going to see if I can make it any better with an edge triggered interrupt.
Here's an I2C address scan at 100 and then 400 (garbage):
Sniffer
Any key to exit
[0x03-0xF7-0xDF-][0x02-0xFF+0xFD-][][[][][[0x02-][0x01+][0x00-][0x04-][0x03-0x04
-0x05-0xFF+0xFF+0xFF+0xFF+0xFF+0xFF+0xFF-][0x00-][0x01-0x02-0x03-0x04-0x05-][0x0
0-][0x01-][0x02-][0x03-][0x04-][0x05-][0x06-][0x07-][0x08-][0x09-][0x0A-][0x0B-]
[0x0C-][0x0D-][0x0E-][0x0F-][0x10-][0x11-][0x12-][0x13-][0x14-][0x15-][0x16-][0x
17-][0x18-][0x19-][0x1A-][0x1B-][0x1C-][0x1D-][0x1E-][0x1F-][0x20-][0x21-][0x22-
][0x23-][0x24-][0x25-][0x26-][0x27-][0x28-][0x29-][0x2A-][0x2B-][0x2C-][0x2D-][0
x2E-][0x2F-][0x30-][0x31-][0x32-][0x33-][0x34-][0x35-][0x36-][0x37-][0x38-][0x39
-][0x3A-][0x3B-][0x3C-][0x3D-][0x3E-][0x3F-][0x40-][0x41-][0x42-][0x43-][0x44-][
0x45-][0x46-][0x47-][0x48-][0x49-][0x4A-][0x4B-][0x4C-][0x4D-][0x4E-][0x4F-][0x5
0-][0x51-][0x52-][0x53-][0x54-][0x55-][0x56-][0x57-][0x58-][0x59-][0x5A-][0x5B-]
[0x5C-][0x5D-][0x5E-][0x5F-][0x60-][0x61-][0x62-][0x63-][0x64-][0x65-][0x66-][0x
67-][0x68-][0x69-][0x6A-][0x6B-][0x6C-][0x6D-][0x6E-][0x6F-][0x70-][0x71-][0x72-
][0x73-][0x74-][0x75-][0x76-][0x77-][0x78-][0x79-][0x7A-][0x7B-][0x7C-][0x7D-][0
x7E-][0x7F-][0x80-][0x81-][0x82-][0x83-][0x84-][0x85-][0x86-][0x87-][0x88-][0x89
-][0x8A-][0x8B-][0x8C-][0x8D-][0x8E-][0x8F-][0x90-][0x91-][0x92-][0x93-][0x94-][
0x95-][0x96-][0x97-][0x98-][0x99-][0x9A-][0x9B-][0x9C-][0x9D-][0x9E-][0x9F-][0xA
0-][0xA1-][0xA2-][0xA3-][0xA4-][0xA5-][0xA6-][0xA7-][0xA8-][0xA9-][0xAA-][0xAB-]
[0xAC-][0xAD-][0xAE-][0xAF-][0xB0-][0xB1-][0xB2-][0xB3-][0xB4-][0xB5-][0xB6-][0x
B7-][0xB8-][0xB9-][0xBA-][0xBB-][0xBC-][0xBD-][0xBE-][0xBF-][0xC0-][0xC1-][0xC2-
][0xC3-][0xC4-][0xC5-][0xC6-][0xC7-][0xC8-][0xC9-][0xCA-][0xCB-][0xCC-][0xCD-][0
xCE-][0xCF-][0xD0-][0xD1-][0xD2-][0xD3-][0xD4-][0xD5-][0xD6-][0xD7-][0xD8-][0xD9
-][0xDA-][0xDB-][0xDC-][0xDD-][0xDE-][0xDF-][0xE0-][0xE1-][0xE2-][0xE3-][0xE4-][
0xE5-][0xE6-][0xE7-][0xE8-][0xE9-][0xEA-][0xEB-][0xEC-][0xED-][0xEE-][0xEF-][0xF
0-][0xF1-][0xF2-][0xF3-][0xF4-][0xF5-][0xF6-][0xF7-][0xF8-][0xF9-][0xFA-][0xFB-]
[0xFC-][0xFD-][0xFE-][0xFF-][0x01+][0x03+0x05+[][[]][][][0x1F-0x21-[[[]][[[[[[]]
[[0x1E-[0x3F+[][]][[][0x0F-]][[]][[[[0x61+[[][[]][0x71+[][0x3B+0x3D+[0x3D+[]][[[
]][[]][][]][[[[]][[[][[[0x71+[[[[[]][]][[]][[[[]][[[[[][][[[]][]][[][[][[0xFD+[[
][[]][][[]][[[]][0x9D-0x9F+[[[[]][][0x8F+[]][[0x99+[[0xBF-][[[]][][[[[[[[][[[[[[
[[][[[[]][][[]][[0xC3-[[][0xC7-[][[][]][[]][[[]][[[0xF1-[[][[[[0xC1-][[]][[0xEF+
][[]][]][0xEF-0xF0-[0xF1-[0xF7+][[[0xF8-[0xF3+[]][[[0xFF-
I2C>
I shifted stuff around and it seems to work slightly better at 400khz, but still nowhere near usable. I don;t think the edge interrupts make a lot of sense here, maybe for the data acquisition phase.
Any key to exit
[0x00-[0x03+0x03+0x07+0x05+0x05-[0x06-[][0x11+[][][0x09+0x0D-[0x0D+0x0F-[0x21+0x
23+0x11-0x07+0x14-[][0x16-[][][][0x35+0x1B-[0x1D+][0x1E-[0x3F+0x20-[][][0x25+0x2
7+][][][][0x29+][][0x37+][][][0x2F+][][0x65+][][][0x35+0x37+0x71+][][][][0x3B+0x
3D+][0x40-[0x43+0x42-[0x47+][0x8B+0x8D+0x0F+0x51+0x53+][][0x4C-[][][0x5F-][0x51-
[0x53+0x67+][0x55+][0x4F+][0x59-[][0x5B-[][0x7B+0xBD+0x5F+][][0x62-[][][][0x4D+0
x67-[0x69+0x69-[][0x6B+0x6C-[0x6B+0x6E-[0x6F-[0x70-[][0x71-[0x72-[]][][0x76-[0x7
F-][0x79-][][][0x7B-][0x7F-[][0x81-[0x82-[0x87+][0x87+][0x87+0x91+][[][0x8C-[][0
x9D+0x9F+0x91-0x93+][0x87+][][0xAD+]][0xB3+0x95+0xB7+][0x3B+0x3D+][0xA0-[[0xA5+]
[][][0xA7+][0xA8-[0xA3-][][0xB9+][][][0xB0-[][][][0xB4-[][][][0xB9-][][][0xBC-[0
x7B+0xBF-0xBF-0xC0-[0x83+][0xC3-[][0xC5-[0xC7+][0xC1+0x93+][0x97+][0xCD-[0xCE-[]
[0xD1+0xD1-[0xA5+0xD3-[0xD4-[0xD5-[][][0xD8-[][][0xDB-[0xDD+0xBB+][][][][0xC5+0x
E3-[][][][][0xE9+][][][0xD9+0xED+0xEE-[][0xF1+0xE3+][][][0xF5-[[0xF7+][][][0xFB-
[[0xFD-[0xFD+0xFF+]
It's still nice to have better code that uses less memory and program space, and is faster.
IT would be good to add a buffer overflow handler for the UART buffer to both the SPI and I2C sniffers. I'm not 100% sure how it's currently done if the ring buffer overflows. I think randomly dropped bytes.
I guess it doesn't make sense to resync I2C because it's synced by start anyways.
*SPI Sniffer hardware test update (needs to be finalized)
*Updated I2C sniffer
*corrected LSB/MSB display quirks
*added LSB to all modes
*added | command (keep?)
Still on my to do list
*terminal text review and protocol documentation
*PIC extensions to raw2wire (need to get the piratepicprog app to stop segfaulting)
*flashrom followup (need to hear back from some users or developers)
Every mode allows pullups, so I removed that message and all the .allowpullup, and switched to a no pullup in hiz check. So far 5.3 is almost 100words smaller than 5.2.
I reviewed the terminal text and tried to make everything a little more consistent. Bus operations are capitalized, otherwise messages use lower case. No period. ON and OFF are always big, removed references to TMS pin. Error messages start ERROR:.
Now we're almost 200 words smaller than v5.2 :)
I'll probably push this without the last two items because I'm still waiting on stuff, and I'd like to fix the l/L bug in v5.2.
Is there anything you want to put in a v5.3 release?
Where do we go from here? I think we could save a bit by doing BBIO2 in a logical way like newterm. We could do it without breaking OpenOCD support, but the regular binary bus modes will be toast.
to do:
*Clean up SPI sniffer
*SPI LCD library (v5.4??)
Hi, I don't think you will be able to make the I2C sniffer run @ 400khz with realtime output, the UART just wastes too many cycles :( perhaps if the scanner was interrupt based/triggered a compromise could be found, the scanner could gather info and the main loop could spit out the results via UART and as long as there wasn't a constant stream and the buffer was big enough, the main loop might have a change of keeping up, but also there might be overheads with a interrupt based routine, pushing and popping all the regs on each trigger would waste alot of cycles, just a few thoughts anyways :)
Hey Darren - The scanner is based on (polled) change notice interrupts, but a true interrupt routine would probably work better. The UART output is buffered with a 4096 ring buffer so quite a bit of stuff can be snooped before it runs out of space.
Hi Ian, just had another looked at UARTbuf() and UARTbufService() when I'd first looked at them I just decided to skip them as they seemed a bottleneck, firstly being calls and for some reason I'd read UARTbufService() as actually waiting till the buffer was empty to output a byte, but i see now it checks if the buffer is free and if so sends a byte, one of the things that was causing slowness in the original sniffer was the I2Csniff structure, everytime members where accessed it was wasting cycles, rotating or anding off bytes, I see the UART buffer routines uses structures again, but they are static so I guess they compile out to static addresses fine ? Must admit when I read code, especially on time critical routines, I get my optimization head on, its surprising how many cycles simple high level functions can take, when i coded that alternative scanner, I ran it through the dissembler a number of times to see what was happening, I think you are able to use the -O compiler flag (Level 1 Optimize) even in the free version of the compiler, this should use alot more of the PICs registers, rather than using stack based variables and increase speed, maybe improve code size as well ??
Off the top of my head, U1STAbits.UTXBF could be checked in the main scanner loop and if free then do the call, haha I'm off again with the optimization head
You guys do great work btw :)
I updated baseio and i2c to eliminate the structs (just in case, but the terminal output is still attached to a messy struct....). I also added the uart check in the I2C loop to save jumping if there's no need.
Feel free to give it some more optimization :) I'll push any changes into the v5.3 release later this week.
[quote author="Darren"]
Hi Ian, just had another looked at UARTbuf() and UARTbufService() when I'd first looked at them I just decided to skip them as they seemed a bottleneck, firstly being calls and for some reason I'd read UARTbufService() as actually waiting till the buffer was empty to output a byte, but i see now it checks if the buffer is free and if so sends a byte, one of the things that was causing slowness in the original sniffer was the I2Csniff structure, everytime members where accessed it was wasting cycles, rotating or anding off bytes, I see the UART buffer routines uses structures again, but they are static so I guess they compile out to static addresses fine ? Must admit when I read code, especially on time critical routines, I get my optimization head on, its surprising how many cycles simple high level functions can take, when i coded that alternative scanner, I ran it through the dissembler a number of times to see what was happening, I think you are able to use the -O compiler flag (Level 1 Optimize) even in the free version of the compiler, this should use alot more of the PICs registers, rather than using stack based variables and increase speed, maybe improve code size as well ??
Off the top of my head, U1STAbits.UTXBF could be checked in the main scanner loop and if free then do the call, haha I'm off again with the optimization head
You guys do great work btw :)
[/quote]
I tried once to try the different optimization setting but every one broke the functionality even the -O1. I think making the global vars volatile would solve it. Never looked more into it because we managed to squeeze it (almost) in (and needed to add/change lots of other things). It was a quick check and without reading what optimization level 1 exactly does (i guess lots of caching ;))
BTW using interrupt would be much better ;)
Guys,
a feature I'd find pretty cool to have is a history (like the 'H' option), but by pressing up / down you can navigate into and edit the command (like in a shell). It can become interesting especially when working in raw modes where you are playing at the bit level.
c0
I agree, that's been on my wish list for some time :)
*Fixed CS message in raw3wire
[ said CS disable in v5.2.
Selectable CS polarity would be nice, but SPI setup is already so long....
It should be in because it is more intuitiver and consistent.
V5.3 is up for download. I'll unsticky this post and make one for v5.4. It sounds like selectable CS is on the todo list for v5.4.