P2 smart pins I2C and SPI mode 3 configuration!
Hi All,
Does anyone have an example of I2C bus using the smart pins? I am currently bit-banging the bus and it works but looks like the timing isn't ideal. I would like something a bit more reliable.
I know I can bit-bang SPI and get fairly decent results at low speeds but fear that at higher speeds say like 4 or even 8 MHz I would need to use the P2 smart pins to clock data in and out reliably. The application I am using the SPI bus for requires high reliability. The SPI bus will be controlling high-power stepper drivers and the bus will be active the entire time sending control data and receiving status information.
I have found a few discussions here and there about SPI but nothing much about smart pins and SPI. Does anyone have examples of SPI mode 3? I need to send 40 bits per transaction (five bytes). The chips will be daisy-chained to create a long shift register. So this long shift register would be 40 bits x the number of drivers connected to the bus.
Any help is greatly appreciated and I know you all don't disappoint
Comments
There is no smart pin I2C mode. You can use pin configuration features to enable pull-ups if you don't have physical resistors on the bus. Again, I'm a Spin programmer, but I think Ross has made it pretty easy to employ the same features in Catalina.
You can to SPI with smart pins. I've attached a simple flash interface for the P2 that uses this the SPI modes (one for MOSI, one for MISO, one for SCLK). For mode three, you'll want to invert the clock. Change this line
to
Thanks Jon I will give it a try
Did you mean i2c or SPI here ?
i2c is usually just bit-banged, as the speeds are modest, and some live checking is needed for ACK or clock stretch (if done by slaves)
START and STOP would always be managed in SW, but I suppose in theory you could use burst clocking and two parallel smart pins in 9 bit TX/RX to send/check data and acks.
SW vs HW should not really be any less reliable, the advantage of HW is that the SW has more time to do other stuff
If you have high power systems and chances of live connection, you may like to add checks for clock glitches.
That's where an external spike is large enough to be seen by any one of the daisy chain parts.
One check is to create a ring, ie have the last output feed back into P2 to be checked for alignment.
I need both I2C and SPI. Ah, I see what you mean. Maybe with I2C it has to be bit banged. I'm used to microcontrollers having the hardware peripherals to do this sort of stuff for me. I have become lazy with this and now using the P2 I have to get creative and make the protocols from examples everyone provides which isn't bad it's just different.
Well, I would sleep better at night knowing the bits are twiddling like they should, and the machine isn't going to cause any problems in operation. I am thinking of safety here more than anything.
Yes, when I design the board, it will have safety built in for scenarios like this.
A heads-up on high-performance data rates:
Tx smartpins are impacted by some I/O staging registers. You won't notice it at slower data rates but once you are approching sysclock frequency (A low divider ratio) you'll start to see a data phase lag with respect to SPI clock. Divider ratios below 8 are very obvious and need attention to compensate - Usually flip the clock edge as a start.
Rx smartpins don't have to worry about the staging registers as there the signal paths are identical for both data and clock. They can operate up to sysclock/3 ratio.
That's for when the Prop2 is the master device. As s slave device there's another extra problem of the SPI clock pins not being true clock inputs so there is a extra level of clock jitter introduced between the external SPI clock and the Prop2's internal sysclock.
Even where MCU have had i2c peripherals, for master i2c I've tended to use SW.
I've enabled the hardware only when i2c slave mode was needed.
IIRC there is also some pin filtering available, but not easy to find full info.
That could allow a higher sysclk to give a majority vote noise filter, at least for the P2 4~8MHz SPI. It does not help the remote chips.
Data mentions
100 A, B, both filtered using global filt0 settings
101 A, B, both filtered using global filt1 settings
110 A, B, both filtered using global filt2 settings
111 A, B, both filtered using global filt3 settings
and a diagram appears here, tho I thought the filter CLK was variable ?
https://forums.parallax.com/discussion/comment/1519013/#Comment_1519013
I will buffer the remote chips to give more drive strength. I'll look into the filtering stuff. Thank you for pointing this out
Hi Jon,
What are these: %0_00000, %1_00000, 1_000? What do they do? Are they binary?
Yes, in Spin, % designates binary, and $ designates hex.
Ah, ok, I thought so I just wanted to make sure. Now when you write say for instance:
%0_00000 it equals: 0
%1_00000 it equals: 1
1_000 equals: 1000
Is the underscore sort of like a comma separator? Did I get that right?
I also noticed this:
x.word[0] := 2 #> (clkfreq / (khz * 1_000)) <# $FFFF ' ticks in period
x.word[1] := x.word[0] >> 1 ' ticks in low cycle (50%)
Is the x.word a struct or is it an array of 2?
Also, what does the #> and <# do?
Is there a SPIN2 to C syntax chart explaining what these operators do?
yes.
0b100000 or 0x20 or 32 in C.
0b1000 or 8 in C.
Yes, just for visuals. The usual reason for placement of underscores is to indicate the hardware's bit groupings within a mode word.
No. The underscore is ignored by the Spin compiler; %100000 is decimal 32.
In Spin, one can have longs (32 bits), words (16 bits), and bytes (8 bits). Subsections of a value can be isolated, hence x.word[1] is the high 16 bits of x, x.byte[0] is the low 8 bits. You're correct in thinking that a long can be treated as an array of two words, or an array of four bytes. A word can be treated as an array of two bytes. Spin treats all variables as arrays of bits, so I could do something like this:
This are the minimum (floor) and maximum (ceiling) operators. I use that particular style to constrain a value between two endpoints
... forces x to be at least two and no more than $FFFF. Another way:
Not that I'm aware of. This link will take you to the operators section of the online Spin2 docs
-- https://docs.google.com/document/d/16qVkmA6Co5fUNKJHF6pBfGfDupuRwDtf-wyieh_fbqw/edit#heading=h.tztltoskeb64
Kind of an array. WORD means a 16-bit memory access using double-byte sized indexing starting from the symbol's address. The symbol doesn't have to be any specific type or size - No safeties, all memory addressable.
Bounding like min()/max(). I keep forgetting which is which and have to look them up every time.
There is the Spin2 manual, see Google Doc named "Spin 2 Language Documentation" - https://www.parallax.com/propeller-2/documentation/
Thank you for this
Ahhh, ok, I see now. SPIN2 is different and hard to wrap my brain around...
Ok, thank you. I think I know of a way to write the bounds in c
On an off topic question, how sensitive are the P2 pins? Can they be damaged easily by ESD or other weird events? For some reason I can't get pin 0 to toggle for the life of me
Is it only pin P0? Often the common pin group all fails together. The Eval Boards had groups of eight pins commoned to each LDO regulator ... so they would fail in groups of eight when accidentally using 5 volts or something.
Evan (as always) makes great points about the pins. I have found them to be pretty rugged, once wiring a 5v output from a device to an output pin on the P2; it seemed to kill the pin -- until the next day when the pin started working again. I can only guess, but the short may have overheated the output driver and when it cooled it started working again.
If I may make an observation: you ask a lot of question (good!) but you rarely, if ever, share snippets of code that are giving you problems (bad). Paraphrasing Jerry Maguire, "Help others help you by sharing the code that is not working as you wish."
In C you could make small changes
or, perhaps his is more efficient
I screwed the pooch on pin 0 somehow or somewhere in the code it's being held low somehow but I looked and cannot find it errrgh. Pins 1 through 7 work fine which is really weird...
I did this:
typedef union
{
struct {
uint16_t x_sclk_lsb; // X val lower
uint16_t x_sclk_msb; // X val upper
}x_sclk_s;
uint32_t x_sclk_byte;
}x_sclk_t;
x_sclk_t x_sclk_reg;
And then did this:
x_sclk_reg.x_sclk_s.x_sclk_lsb = x_sclk_reg.x_sclk_s.x_sclk_lsb >= 2 && (_clockfreq() / (spi_clk_freq * 0x8)) && x_sclk_reg.x_sclk_s.x_sclk_lsb <= 0xFFFF;
x_sclk_reg.x_sclk_s.x_sclk_msb = x_sclk_reg.x_sclk_s.x_sclk_lsb >> 1;
I know it looks like a disaster
I'm ashamed of my poor programming mistakes lol. I don't have a degree in computer science, so I am learning as I go. I know C pretty well but not the greatest at it. All of you are smarter than me for sure
Yeah, I see the regulator groups on the schematic. It is really odd that it is ONLY pin 0. I use _pinl(0); and _pinh(0); to try and toggle it but nothing. Pins 1 through 7 are fine and can toggle them all day long so I must have done something stupid.
Are you trying that in a fresh program? If you've written some sort of smart mode to Pin 0, that could cause it to not react to drive.
Your words... My mentor was an old-school character actor named Cliff Osmond. He was discovered by the legendary director, Billy Wilder, and did several movies with Walter Matthau and Jack Lemmon (who sponsored him into the Academy). Cliff was a very smart man, which lead him to teaching (acting). One of his admonitions was, "Always go for simplicity, because simplicity is elegance, and elegance is best."
Again, I'm not a C programmer (though I understand the C syntax), so I might translate my SPI connections to the P2 flash like this (not tested).
I know that my code is verbose -- my goal is clarity. Note that I de-activate (reset) the SPI MOSI and MISO pins until they're used.
Um... 16 in decimal. $10 in hexadecimal (spin2), right? (and, 0x10 in C)
0b1000 is 8 (there are only three 0s to the right of 1). I had to zoom in.
I looked and couldn't find anything that jumps out at me