P2 simple SPI flash memory driver

PRI Spi_Init() | div
div:= (clkfreq / 100_000_000) #> 4 ' adjust smart pin base period to actual frequency
ORG
fltl #spi_di ' reset smart pins
fltl #spi_do
wrpin ##modeClk,#spi_ck ' smart pin transition mode
wrpin ##modeTXD,#spi_di ' smart pin synchronous serial transmit
wrpin ##modeRXD,#spi_do ' smart pin synchronous serial receive
wxpin div,#spi_ck ' clock transition base period
drvl #spi_ck ' enable smart pin
END
I would like to know with which clock the SD card is driven, if the clkfreq is 256Mhz.
Thanks
Comments
Since it is using transition mode, the effective clock is
clkfreq/(div*2)
.For clkfreq = 256_000_000 that obviously comes out to... 4. Which it will always do since 500_000_000 is not a valid clkfreq.)
So the clock frequency comes out to 32 MHz
wxpin ( P2clk / ( SPIclk * 2 ) ) << 16 , #spi_ck
wxpin (256,000,000 / ( 5,000,000 * 2 ) ) << 16 , #spi_ck
That's what I understood from the documentation.
Is that correct?
No, the *2 is because of the transition mode. As the name implies, the divider values counts the cycles between level transitions (i.e. high-to-low and low-to-high), so the overall period is twice the divider value.
Also, no <<16
Ok
256,000,000÷2÷26 would be the correct way to calculate the value of wxpin? To get a takt of 5.000.000?
Checks out, value should be 26
I'm a simpleton: I prefer to use pulse mode for the SPI clock. This the setup from my simple flash interface object.
pub start(khz) | m, x '' Configure SPI for coms with flash '' -- khz is clock frequency in kilohertz pinh(SF_CS) ' deselect flash m := P_SYNC_RX ' spi rx mode m |= ((SF_SCK-SF_SDI) & %111) << 24 ' add SCK offset (B pin) x := %0_00000 | (8-1) ' sample ahead of b pin rise, 8 bits pinstart(SF_SDI, m, x, 0) ' configure smart pin pinf(SF_SDI) ' reset/disable until used m := P_SYNC_TX | P_OE ' spi tx mode m |= ((SF_SCK-SF_SDO) & %111) << 24 ' add SCK offset (B pin) x := %1_00000 | (8-1) ' start/stop mode, 8 bits pinstart(SF_SDO, m, x, 0) ' activate smart pin pinf(SF_SDO) ' reset/disable until used m := P_PULSE | P_OE ' spi clock mode x.word[0] := 2 #> (clkfreq / (khz * 1_000)) <# $FFFF ' ticks in period x.word[1] := x.word[0] >> 1 ' ticks in low cycle (50%) pinstart(SF_SCK, m, x, 0)
This lets you set the number of bits in the transaction very easily
pri shiftout(value, bits) | x '' Shift out bits from value org ror value, bits ' msb to bit32 rev value ' reverse for S/P LSBFIRST output mov x, bits ' set # of output bits sub x, #1 or x, #%1_00000 wxpin x, #SF_SDO wypin value, #SF_SDO ' set output value drvl #SF_SDO ' arm SPI TX wypin bits, #SF_SCK ' clock bits out nop testp #SF_SCK wc ' wait for clocking to finish if_nc jmp #$-1 fltl #SF_SDO ' disable SPI TX end
A warning: don't use too low frequency for the flash while SD is inserted. I managed to "unformat" the SD with 2 MHz clock for the flash (sector 0 overwritten). After testing a flash related (working) code there were no more files on the SD.
I raised the flash clock to 20 MHz, no more SD problems.
Use SPI clock mode 3 (CPOL=1, CPHA=1) to avoid incorrect device selection. That keeps the two clocks high during idle, which is important so as not to select the other device when idle. I've converted FlexC's SD driver to do this.
The alternative mode 0 workaround is a convoluted device select sequence for each access to each device.
Jon's code above only needs the clock inverted and it'll work fine as mode 3.
m := P_PULSE | P_OE | P_INVERT_OUTPUT ' spi clock mode
Wuerfel_21 is that correct?
I want to write first of all a sector of a SD card.
What surprises me that in the original only 256 bytes stand should it not be 512?
CON CLK_FREQ = 256_000_000 ' system freq as a constant _clkfreq = CLK_FREQ CON spi_cs = 3 spi_ck = 2 spi_di = 1 ' P2 -> flash spi_do = 0 ' flash -> P2 modeCLK = P_TRANSITION + P_OE + P_INVERT_OUTPUT ' SPI_CK modeTXD = P_SYNC_TX + P_OE |((spi_ck - spi_di) & %111)<<24 ' + P_SYNC_IO + P_FILT0_AB modeRXD = P_SYNC_RX |((spi_ck - spi_do) & %111)<<24 Write_Enable = $06 Erase_4k = $20 Erase_64k = $D8 Write_Page = $02 Read_Data = $03 Read_Status = $05 div = (_clkfreq / (2 * 5_000_000)) #> 4 ' adjust smart pin base period to actual frequency DAT org 0 asmclk '+------------------------------------------------------------------------------------------------------------------------------+ '+------------------------------------------------------------------------------------------------------------------------------+ 'PUB Spi_Init() | div ' div:= (clkfreq / 100_000_000) #> 4 ' adjust smart pin base period to actual frequency ' ORG fltl #spi_di ' reset smart pins fltl #spi_do wrpin ##modeClk,#spi_ck ' smart pin transition mode wrpin ##modeTXD,#spi_di ' smart pin synchronous serial transmit wrpin ##modeRXD,#spi_do ' smart pin synchronous serial receive wxpin div,#spi_ck ' clock transition base period drvl #spi_ck ' enable smart pin ' END '+------------------------------------------------------------------------------------------------------------------------------+ mov cmd, #Write_Enable '+------------------------------------------------------------------------------------------------------------------------------+ 'PRI Spi_Cmd8(cmd) ' ORG drvh #spi_cs shl cmd,#24 ' shift command up rev cmd drvl #spi_cs wxpin #$27,#spi_di ' 8 bits, start/stop mode wypin cmd,#spi_di drvl #spi_di ' enable TX smart pin wypin #16,#spi_ck ' start CLK sequence (16 transitions = 8 pulses) nop .waitRdy2 testp #spi_ck wz ' IN=1 if smart pin ready if_nz jmp #.waitRdy2 ' wait until last CLK sequence finished ' END '+------------------------------------------------------------------------------------------------------------------------------+ mov cmd, #Write_Page mov adr, #flashAdr '+------------------------------------------------------------------------------------------------------------------------------+ 'PRI Spi_Cmd32(cmd, adr) ' outputs 4 bytes: 8 bit command + 24 bits adr ' ORG drvh #spi_cs shl cmd,#24 'shift command up or cmd,adr 'or in address drvl #spi_cs ' END ' Spi_WrLong(cmd) '+------------------------------------------------------------------------------------------------------------------------------+ mov data, cmd '+------------------------------------------------------------------------------------------------------------------------------+ 'PRI Spi_WrLong(data) ' outputs 32 bits (MSB first) while spi_cs stays low ' ORG rev data wxpin #$3f,#spi_di ' 32 bits, start/stop mode wypin data,#spi_di drvl #spi_di ' enable TX smart pin wypin #64,#spi_ck ' start CLK sequence (64 transitions = 32 pulses) nop .waitRdy3 testp #spi_ck wz ' IN=1 if smart pin ready if_nz jmp #.waitRdy3 ' wait until last CLK sequence finished ' END '+------------------------------------------------------------------------------------------------------------------------------+ mov data, puffer '+------------------------------------------------------------------------------------------------------------------------------+ rep1 'PRI Spi_WrLong(data) ' outputs 32 bits (MSB first) while spi_cs stays low ' ORG rev data wxpin #$3f,#spi_di ' 32 bits, start/stop mode wypin data,#spi_di drvl #spi_di ' enable TX smart pin wypin #64,#spi_ck ' start CLK sequence (64 transitions = 32 pulses) nop .waitRdy2 testp #spi_ck wz ' IN=1 if smart pin ready if_nz jmp #.waitRdy2 ' wait until last CLK sequence finished ' END add data, #4 '+------------------------------------------------------------------------------------------------------------------------------+ rep 128,#rep1 ' 128*4 = 512 = 1 Sector '+------------------------------------------------------------------------------------------------------------------------------+ drvh #spi_cs '+------------------------------------------------------------------------------------------------------------------------------+ ' ################# loop2 jmp #loop2 '+------------------------------------------------------------------------------------------------------------------------------+ flashAdr long $60000 ' später ab 0 puffer long $1000 '+------------------------------------------------------------------------------------------------------------------------------+ cmd long 0 adr long 0 data long 0
Source: https://github.com/parallaxinc/propeller/tree/master/libraries/community/p2/All/Simple_SpiFlash
That's a flash driver, not an SD driver
Sorry Wuerfel_21 was already on the other topic, it was about SD cards.