|
|
View previous topic :: View next topic |
Author |
Message |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
simple bitbang SPI ram driver faults ODD addresses [SOLVED] |
Posted: Fri Dec 30, 2016 9:21 am |
|
|
compiler 5.064
I am certain i did something boneheaded here -but can't
for the life of me see it in this 128K byte SPI ram byte wide
bit bang driver for the 23LC1024 SPI SRAM
All the even addresses seem to work but the odd ones are wrong
by the absence of the low order bit -- ret data SHOULD look like
65,65,17,17, -!- 65,65,17,17,test33
but in reality the odd addresses on the right side of the -!- are wrong
it actually outputs
65,65,17,17, -!- 64,64,16,16,test33
datasheet at
http://www.mouser.com/ds/2/268/25142A-47786.pdf
Code: |
// 23LC1024 24 bit address single byte SPI RAM bit bang
#include <18f46K22.h>
#fuses HSM,NOPLLEN,NOFCMEN,NOIESO,PUT,NOBROWNOUT
#Fuses CCP2C1,NOPBADEN,NOMCLR,NOSTVREN,NOLVP,
#Fuses NOPBADEN,NOMCLR,NOSTVREN,NOLVP,
#fuses NOXINST,NODEBUG,NOPROTECT,NOCPB,NOCPD,NOWRT,NOWRTC
#Fuses NOWRTB,NOWRTD,NOEBTR,NOEBTRB
#use delay( clock=16588888) // clock xtal
#use rs232(baud=57600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use fast_io(D)
#include <stdlib.h>
#include <stdio.h>
#define SRLS pin_d0
#DEFINE SROUT pin_D1
#define SRDIN pin_d2
#define SCLK pin_d3
#define mhz64 100
// PIC portd tris low bits: out,in,out,out
// shift off hi order bit and clock out
void write8(unsigned int8 bt){
unsigned int8 c;
#bit b=bt.7
for (c=0;c<8; c++){
if (b) output_high (SRDIN);
else output_low(SRDIN);
delay_us(mhz64); output_high(SCLK); delay_us(MHZ64); output_low(SCLK);
bt <<=1; delay_us(MHZ64);
}//end for
}
void writeadd ( unsigned int32 add ){
unsigned int8 c; // shifting hi order bit int 25th bit location
#bit a=add.24
for (c=0;c<24;c++){ // address
add<<=1;
if (a) output_high (SRDIN);
else output_low(SRDIN);
delay_us(mhz64); output_high(SCLK); delay_us(mhz64); output_low(SCLK);
delay_us(mhz64);
}}
// write byte to address
void W_SR( unsigned int32 addr, unsigned int8 d){
output_low(SRLS); write8(2); // command to write-a-byte
writeadd(addr);
write8(d); output_high(SRLS);
}
//read byte from address
unsigned int8 R_SR(unsigned int32 addr){
unsigned int8 i=0,c;
#bit r=i.0
output_low(SRLS); write8(3); // command to read abyte
writeadd(addr); // next read the byte
for (c=0; c<8; c++){
delay_us(mhz64);
output_high(SCLK);
delay_us(mhz64);
if (input(SROUT)) r=1;
else r=0;
if(c<7) i <<=1; // don't shift last bit
output_low(SCLK);
}
output_high(SRLS); return(i);
}
// command to set to byte r/w mode
void SR_setmode(void){
output_low(SRLS); delay_us(mhz64);
write8(1); // command
write8(0); // to set byte mode
delay_us(mhz64); output_high(SRLS);
}
//
main(){
//******
output_d(1); set_tris_d(0b11110010); output_low (sclk); //next wake chip
delay_ms(500); output_low(SRLS); delay_ms(10); output_high(SRLS); delay_ms(10);
sr_setmode(); //byte mode set - then load values into different addresses
W_SR(10,65); W_SR(14,65); W_SR(12,17); W_SR(2156,17);
W_SR(11,65); W_SR(37123,65); W_SR(37133,17); W_SR(13,17);
while(1) {
printf("%u,", R_SR(10)); printf("%u,", R_SR(14)); printf("%u,", R_SR(12));
printf("%u,", R_SR(2156));
printf ("-!-");
printf("%u,", R_SR(11)); printf("%u,", R_SR(37123));
printf("%u,", R_SR(37133)); printf("%u,", R_SR(13)); printf("test 33 \r");
delay_ms(1000);
} // end MAIN - WHILE
} // end main
|
Last edited by asmboy on Fri Dec 30, 2016 2:42 pm; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 30, 2016 11:48 am |
|
|
I notice in your R_SR() routine, you don't handle SCLK the same way
that you do in all other commands. You do it like this:
Quote: | for (c=0; c<8; c++){
delay_us(mhz64);
output_high(SCLK);
delay_us(mhz64);
if (input(SROUT)) r=1;
else r=0;
if(c<7) i <<=1; // don't shift last bit
output_low(SCLK);
} |
To keep the same method, it should be done like this:
Quote: | for (c=0; c<8; c++){
delay_us(mhz64);
if (input(SROUT)) r=1;
else r=0;
if(c<7) i <<=1; // don't shift last bit
output_high(SCLK);
delay_us(mhz64);
output_low(SCLK);
} |
The main question is why do this ? CCS has files such as 25640.c
which contain a template that could be modified for your eeprom.
Just remove the ext_eeprom_ready() code, and remove the for() loop
that sends the WREN byte, and it would probably work. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Dec 30, 2016 2:41 pm |
|
|
THKS PCM !! I
adapted the similar example from CCS and am up and running.
One thing the data sheet does not make clear -
in byte mode there are 131k addresses and it is easy to to adapt
to having a virtual 16 bit int storage array for 65k of those VARS
by simply changing out of BYTE mode - and taking a high level address
call and left shifting it one place.
My ultimate goal is to actually use the part to store variable length strings
from as few as 6 or 8 characters up to the range of about 23 or 24 bytes.
32 bit page mode looks GREAT for doing this in RLL fashion - null terminated.
when using page mode for these parts -
what is NOT obvious is what the address index range is -
is it linear 0=4095 by 'ones'
or is it 0,4096,8192,12288, etc --
can't find doc and unless somebody knows already - i'll have to enter experiment land to find out... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 30, 2016 5:24 pm |
|
|
It says in diagrams 2-3 and 2-4, that the address is 24 bits and consists of
Page X and Word Y. The implications are:
1. If you want to start at the beginning of a page, then send the full
address, with the bottom 5 bits set to zero. So,
Page 0: Address 0x000000
Page 1: Address 0x000020
Page 2: Address 0x000040
Page 3: Address 0x000060
etc.
These addreses are 0x20 apart, because each page is 32 bytes long.
2. Because they say "Word Y", it implies that you could, if you wished,
start the page access at any byte address within the page. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Dec 31, 2016 1:44 pm |
|
|
Thanks PCM for your careful reading-
SO for variable length strings of about 6 or 8 to 20 or 22 bytes or so
page boundary writes make good sense .
i already realized that storing an int8 can be done with a
virtual Array address
that spans a 131k integer range , 1:1
RAM_ADD=virtual_add
for int16 the virtual to real address conversion for 65k addresses is
RAM_ADD=virtual_add<<1
and for 4096 pages of null terminated variable length it becomes
RAM_ADD=virtual_add<<5
going to try this and report if i'm wrong .. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat Dec 31, 2016 2:14 pm |
|
|
The nice thing here is that you can send the single address at the start of the page, and if you have switched the chip to page mode, just carry on writing bytes, and the chip auto increments to write to each successive byte. You should include a limit check so that if it gets to 31 bytes, it then writes a '\0' to terminate your string, and stops (otherwise stopping at the null in your source string). The funny thing is I'm storing string data in a file on an SD card using almost exactly the same layout at the moment. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Dec 31, 2016 2:53 pm |
|
|
Exactly where i'm trying to go Ttelmah-
Basically enable the chip, write the command and address block
and then leave CS low- Then clock out and count bytes as the messages are built - then retrieve when data runs are complete for "export" -
So as data are generated from ADC words and a time signature generator- they are dumped into SP ram -
I just raise CS after the EOL char is sent -
Has to be all bit banged as i can't have access to the already committed SPI hardware in the PIC based instrument i'm upgrading. Plus
The part involved is so cheap it might as well be free compared to all the other costs of doing the upgrade....and adding this tiny PCB and some hay-wires.
Also considering using FRAM should non_V ram make sense to the customer -
As there seems to be pin compatibility there too.
I sincerely believe what i'm doing would be so much harder with any competing compiler too. I've looked at support forums on Microchip -hence feel grateful and lucky for the generous help i've found here. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat Dec 31, 2016 3:22 pm |
|
|
You should be aware it doesn't have to be 'bit banged'.
#USE SPI, can generate software SPI just as easily as hardware based. You can use any pins you want, and it optimises the I/O over the bit banged approach. Even better spi_xfer allows you to specify how many bits to send, so to send a byte, you can use spi_xfer(STREAM_NAME, val, 8); while to send 16bits, just change the 8 to 16. It can also receive 8, 16 or 32bits at a time.
I must admit I always wonder why people are doing it manually now!... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sun Jan 01, 2017 4:32 am |
|
|
As a further comment, do consider the FRAM, or NVRAM. Both have the big advantage of being fast. Writes can be completed as fast as you can clock the data out.
Remember also that you should design your circuit to allow you to always 'complete' the write if something like a power fail happens or long term there may be problems.... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sun Jan 01, 2017 8:17 am |
|
|
re:I must admit I always wonder why people are doing it manually now!...
Well it is hard to teach us 'old dogs' new tricks ! When you grow up manually toggling in boot loaders on PDP8s..need I say more ?
Anyone who started in assembler probably figures they can do code better than in these 'new,fangled' high level languages.....
Jay
Happy New Year |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sun Jan 01, 2017 9:40 am |
|
|
Agreed. However I'm talking here about the large number of 'low mileage' posters who then write things like SPI code, and are wasting time doing it manually, and often getting something wrong....
Here 'asmboy' may well fit your 'assembler' model, but in fact he's already posted back to me directly, that he has now tried using the CCS functions and has this working.
I'm quite resistant to some 'new things', but a library that allows you to generate quite efficient code to clock in/out on whatever edge you want, however many bits are needed etc., is just too useful to ignore.
It's actually one of the best bits of code that has been added to the compiler in recent times.
Happy New Year |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|