Hi Art,
I think the hardware SPI port might do it. I'm going to try these: http://www.mouser.com/ProductDetail/...1pcR43MBP1g%3d. I don't care so much that they're non-volatile but they are much faster at writing than standard EEPROM.
Best,
Paul
Hi Art,
I think the hardware SPI port might do it. I'm going to try these: http://www.mouser.com/ProductDetail/...1pcR43MBP1g%3d. I don't care so much that they're non-volatile but they are much faster at writing than standard EEPROM.
Best,
Paul
Yeap, I must have been smoking something. No way to fit it in.I still think you should have more than enough storage on an 18F452.
The part you highlighted is very cool (fast as SRAM, but non-volatile like SEEPROM). The 16k part will be great for 1024 WORDS, but will only fit half of the 1204 LONGS.
Just wanted to followup with news of success. After a comedy of wiring errors I finally got an F-RAM going using shiftin and shiftout. Once I confirmed that as working I changed the code to use the hardware SPI port. It is blazingly fast. I'm using running the 18F452 at 20MHz so I can "only" run with a 5MHz clock. Haven't actually timed it (yet) but I think it'll all work out just fine.
If there's any interest I'll post the code in the Code Examples section.
Thanks again, everyone, for all the suggestions.
Best Regards,
Paul
I have used the i2c version of the FRAM and liked it. I had to switch when I needed more memory, though... it can cost over 10x the price of an atmel eeprom.
Hello Vinson,
Here it is, warts and all...
Let us know if there are questions or difficulties.Code:'**************************************************************** '* Name : HW_FRAM_SPI_Test.pbp * '* Notes : Demo of using hardware SPI port to read and write * '* : a Ramtron FM25C106-G 16K 5V F-RAM chip. * '* : * '* : Assembled on an Olimex DEV-00021 40-pin * '* : board from Sparkfun. * '* : * '* : Much information on working with the hardware * '* : SPI was gleaned from Jeremy Grotte's * '* : sdfshc32d.pbp file. * '* : * '* : Compiled using PBP v2.60L * '* : * '**************************************************************** ' PIC18F452 DIP Package ' Pin Assignments ' Pin # Use Hookup ' 1 MCLR/VPP To Vdd through 4.7k resistor ' 2 RA0/AN0 n/c, reserved for analog input ' 3 RA1/AN1 n/c ' 4 RA2/AN2/VREF- n/c ' 5 RA3/AN3/VREF+ n/c ' 6 RA4/T0CKI n/c ' 7 RA5/AN4/SS n/c ' 8 RE0/RD/AN5 n/c ' 9 RE1/WR/AN6 n/c ' 10 RE2/CS/AN7 n/c ' 11 Vdd Power, +5V ' 12 Vss Ground ' 13 OSC1/CLKIN To 20MHz crystal ' 14 OSC2/CLKOUT To 20MHz crystal ' 15 RC0/T1OSO/T1CKI n/c ' 16 RC1/T1OSI/CCP2 n/c ' 17 RC2/CCP1 n/c ' 18 RC3/SCK/SCL to F-RAM SCK (pin 6) ' 19 RD0/PSP0 n/c ' 20 RD1/PSP1 n/c ' 21 RD2/PSP2 n/c ' 22 RD3/PSP3 FRAM_CS, to F-RAM CS (pin 1) ' 23 RC4/SDI/SDA SDI, to F-RAM SO (pin 2) ' 24 RC5/SDO SDO, to F-RAM SI (pin 5) ' 25 RC6/TX/CK TX; to MAX232A Pin 11 (goes out from pin 14 to DB9F pin 2) ' 26 RC7/RX/DT RX; to MAX232A Pin 12 (goes out from pin 13 to DB9F pin 3) ' 27 RD4/PSP4 n/c ' 28 RD5/PSP5 n/c ' 29 RD6/PSP6 n/c ' 30 RD7/PSP7 n/c ' 31 Vss Ground ' 32 Vdd Power, +5V ' 33 RB0/INT n/c ' 34 RB1 n/c ' 35 RB2 n/c ' 36 RB3/PGM n/c ' 37 RB4 n/c ' 38 RB5 n/c ' 39 RB6/PGC n/c ' 40 RB7/PGD n/c 'Notes '----- 'SETUP RS232: 'Target device uses 115200 baud, 8 bits, 1 stop bit, flow control = none '-------------------------------------------------------------------------------- '### Includes '-------------------------------------------------------------------------------- 'none '-------------------------------------------------------------------------------- '### Defines '-------------------------------------------------------------------------------- DEFINE LOADER_USED 1 DEFINE OSC 20 'Set receive register to receiver enabled DEFINE HSER_RCSTA 90h 'Set transmit register to transmitter enabled, high speed BRGH DEFINE HSER_TXSTA 24h 'Set baud rate DEFINE HSER_BAUD 115200 'automatically clear any USART overflows DEFINE HSER_CLROERR 1 '-------------------------------------------------------------------------------- '### Constants '-------------------------------------------------------------------------------- TRUE CON 1 FALSE CON 0 OCWREN con %00000110 'F-RAM Write Enable Op-Code OCRDSR con %00000101 'F-RAM Read Status Register Op-Code OCWRSR con %00000001 'F-RAM Write Status Register Op-Code OCREAD con %00000011 'F-RAM Read Memory Op-Code OCWRITE con %00000010 'F-RAM Write Memory Op-Code '-------------------------------------------------------------------------------- '### Aliases '-------------------------------------------------------------------------------- SCK Var PORTC.3 ' SPI clock SCK_TRIS Var TRISC.3 ' SPI clock direction SDI Var PORTC.4 ' SPI data in SDI_TRIS Var TRISC.4 ' SPI data in direction SDO Var PORTC.5 ' SPI data out SDO_TRIS Var TRISC.5 ' SPI data out direction FRAM_CS Var PORTD.3 ' F-RAM chip select FRAM_CS_TRIS Var TRISD.3 ' F-RAM chip select direction WCOL Var SSPCON1.7 ' SSP write collision SSPEN Var SSPCON1.5 ' SSP enable SSPIF Var PIR1.3 ' SSP interrupt flag '-------------------------------------------------------------------------------- '### Set Up Registers '-------------------------------------------------------------------------------- ADCON1 = %10001110 'left justified, RA0/AN0 is analog input 'Set up SPI port SSPSTAT = %01000000 ' Sample at middle of data output time, Transmit on idle rising edge of SCK 'SSPCON1 = %00000010 ' SPI master mode, clock = Fosc/64, Clock idle LOW. 'SSPCON1 = %00000001 ' SPI master mode, clock = Fosc/16, Clock idle LOW. SSPCON1 = %00000000 ' SPI master mode, clock = Fosc/4, Clock idle LOW. SSPEN = 1 ' Enable hardware SPI port. '-------------------------------------------------------------------------------- '### Variables '-------------------------------------------------------------------------------- nSPI_Data_In var byte nSPI_Data_Out var byte lVal var long wFRAM_Addr var word '-------------------------------------------------------------------------------- '### Initialization '-------------------------------------------------------------------------------- FRAM_CS = 1 ' F-RAM chip not selected. FRAM_CS_TRIS = 0' F-RAM chip select as output SDO = 1 ' Start SPI data out high SDO_TRIS = 0 ' SPI data out as Output SDI_TRIS = 1 ' SPI data in as Input SCK = 0 ' SPI clock idles low SCK_TRIS = 0 ' SPI clock as Output wFRAM_Addr = $000F ' Set an arbitray memory location lVal = -5000 ' Set lVal to some starting point pause 500 hserout["lVal initalized to ", dec lVal,13,10] 'Jump to Main program goto main '-------------------------------------------------------------------------------- '### Helper Functions '-------------------------------------------------------------------------------- WriteSPI: WCOL = 0 nSPI_Data_In = SSPBUF ' Clear the buffer. SSPIF = 0 ' Clear the interrupt flag. SSPBUF = nSPI_Data_Out ' Send the byte. If (WCOL) Then Return ' Check for write collision. While (!SSPIF) ' Wait for send to complete. Wend Return ReadSPI: nSPI_Data_In = SSPBUF ' Clear the buffer. SSPIF = 0 ' Clear the interrupt flag. SSPBUF = $ff ' Shift out a dummy byte. While (!SSPIF) ' Wait for receive byte. Wend nSPI_Data_In = SSPBUF ' Get the byte. return '-------------------------------------------------------------------------------- '### MAIN PROGRAM '-------------------------------------------------------------------------------- Main: ' Do a write ' Select the F-RAM FRAM_CS = 0 ' Begin with WREN nSPI_Data_Out = OCWREN gosub WriteSPI ' un-select the F-RAM FRAM_CS = 1 ' only one Op-code per chip select!!! ' Select the F-RAM FRAM_cs = 0 ' Next send WRITE OpCode nSPI_Data_Out = OCWrite gosub WriteSPI ' Send two bytes of address (upper 5 bits are "don't care") nSPI_Data_Out = wFRAM_Addr.HighByte '$00 gosub WriteSPI nSPI_Data_Out = wFRAM_Addr.LowByte '$0f gosub WriteSPI ' next byte(s) are data, address will increment with each write nSPI_Data_Out = lVal.Byte0 gosub WriteSPI nSPI_Data_Out = lVal.Byte1 gosub WriteSPI nSPI_Data_Out = lVal.Byte2 gosub WriteSPI nSPI_Data_Out = lVal.Byte3 gosub WriteSPI ' un-select the F-RAM FRAM_CS = 1 ' do a read FRAM_CS = 0 ' Begin by sending the read OpCode nSPI_Data_Out = OCREAD '=READ command gosub WriteSPI ' Send two bytes of address (upper 5 bits are "don't care") nSPI_Data_Out = wFRAM_Addr.HighByte gosub WriteSPI nSPI_Data_Out = wFRAM_Addr.LowByte gosub WriteSPI ' Now read in the value one byte at a time gosub ReadSPI 'one byte into nSPI_Data_In lVal.Byte0 = nSPI_Data_In gosub ReadSPI 'one byte into nSPI_Data_In lVal.Byte1 = nSPI_Data_In gosub ReadSPI 'one byte into nSPI_Data_In lVal.Byte2 = nSPI_Data_In gosub ReadSPI 'one byte into nSPI_Data_In lVal.Byte3 = nSPI_Data_In FRAM_CS = 1 hserout["lVal=",dec lVal,13,10]; ' Add one and write it back to the same location lVal = lVal + 1 goto Main
Best Regards,
Paul
Thanks Paul for your shared codes!!! It is great.
I did the same test, but used PIC16LF877(3.0V) and FM25V10(3.0V,1Mbit). I think the communication is the same, only with some minor modifications. I spent almost one day on it,still get no result yet.... Can you help me to check if there is anything wrong with it?
Thanks!
Code:'**************************************************************** '* Name : HARDWARE_SPI_FRAM TEST.BAS * '* Author : [select VIEW...EDITOR OPTIONS] * '* Notice : Copyright (c) 2010 [select VIEW...EDITOR OPTIONS] * '* : All Rights Reserved * '* Date : 3/17/2010 * '* Version : 1.0 * '* Notes : * '* : * '**************************************************************** '**************************************************************** Define OSC 10 'INCLUDE "modedefs.bas" DEFINE LOADER_USED 1 Define LCD_DREG PORTD Define LCD_DBIT 4 Define LCD_RSREG PORTE Define LCD_RSBIT 0 Define LCD_EREG PORTE Define LCD_EBIT 1 Low PORTE.2 ' LCD R/W line low (W) ADCON1 = %10000010 ' Set PORTA analog and right justify result Pause 500 ' Wait .5 second Low PORTE.2 ' LCD R/W line low (W) ADCON1 = %10000010 ' Set PORTA analog and right justify result Pause 500 ' Wait .5 second Ticks VAR word ' Tick count (61 ticks = 1 sec) Hour VAR byte ' Hour variable Minute VAR byte ' Minute variable Second VAR byte ' Second variable Disp VAR byte ' Disp = 1 to update display ' Interrup handling bits GIE var INTCON.7 PEIE var INTCON.6 TMR2IE VAR PIE1.1 TMR2ON VAR T2CON.2 TMR2IF VAR PIR1.1 ' Definations for the SPI communication protocal '------------------------------------------------------------------ 'TRISB.5=0 ' This is for the CS PIN FM_CS VAR PORTA.5 ' SPI FRAM CHIP CS PIN FM_CS_TRIS VAR TRISA.5 ' SPI FRAM CHIP CS PIN DIRECTION SCK VAR PORTC.3 ' SPI CLOCK SCK_TRIS VAR TRISC.3 ' SPI CLOCK PIN DIRECTION CONTROL SDI VAR PORTC.4 ' SPI DATA IN SDI_TRIS VAR TRISC.4 ' SPI DATA IN PIN DIRECTION SDO VAR PORTC.5 ' SPI DATA OUT PIN SDO_TRIS VAR TRISC.5 ' SPI DATA OUT PIN WCOL VAR SSPCON.7 'SSP WRITE COLLISION SSPEN VAR SSPCON.5 'SSP ENABLE SSPIF VAR PIR1.3 'SSP INTERRUPT FLAG '--------------------------------------------------------------------- '-----------------------A/D setups -------------------------------------------- 'Define ADC_BITS 10 ' Set number of bits in result 'Define ADC_CLOCK 2 ' Set clock source (3=rc) 'Define ADC_SAMPLEUS 20 ' Set sampling time in uS 'TRISA = %11111111 ' Set PORTA to all input 'ADCON1 = %10000010 ' Set PORTA analog and right justify result '------------------------------------------------------------------------------- '-------------SPI PORT REGISTERS SETUP---------------------------------------- SSPSTAT=%01000000 ' SAMPLE AT THE MIDDLE OF DATA OUTPUT TIME, TRANSMIT ON IDLE RISING EDGE OF SCK SSPCON=%00100000 ' SPI MASTER MODE, CLOCK=Fosc/4 ENABLE HARDWARE SPI PORT SSPEN=1 ' ENABLE HARDWARE SPI PORT '------------------------------------------------------------------------------- '---VARIABLES FOR THE ADDRESS AND DATA MANAGEMENT------------------------------- 'TX_LEN CON 1 'SENDING DATA LENGTH TX_BUFF var byte'[TX_LEN] 'SENDING DATA ARRAY 'RX_LEN CON 1 'RECEIVING DATA LENGTH RX_BUFF var byte'[RX_LEN] 'RECEIVING DATA ARRAY ADD VAR WORD 'ADDRESS FOR THE MOMEORY(LOW 16BITS) BLOCK0 VAR BYTE 'HIGH EIGHT BITS OF MEMORY ADDRESS BLOCK1 VAR BYTE 'HIGH EIGHT BITS OF MEMORY ADDRESS '------------------------------------------------------------------------------- '-------------INITIALIZATION-------------------------------------------------- FM_CS=1 'FRAM CHIP DISABLED FM_CS_TRIS=0 'OUTPUT SDO=1 'START SPI PIN WITH HIGH SDO_TRIS=0 'OUTPUT SDI_TRIS=1 'INPUT BLOCK0=%00000000; BLOCK1=%00000001; add=0; B0 Var byte b0=100; X1 VAR BYTE X2 VAR BYTE X3 var BYTE X4 var BYTE 'Delay VAR byte ‘ Used to Debounce button 'TRISA = 0 ‘ PORTA is output 'TRISB = 3 ‘ RB0,RB1 are inputs 'CMCON = 7 ‘ PORTA digital I/O 'PAUSE 500 ‘ Wait 0.5sec for LCD to initialize ' ' Clear Hour, Minute, Second and Ticks to zero ' Hour = 0 Minute = 0 Second = 0 Ticks = 0 ' T2CON=%01001100 ' Set the prescaler to 1, and postscale to 10 ON INTERRUPT GOTO ISR ' ISR routine 'PR2=156 ' Set PR2 Register 10ms for timer2 'PR2=249 ' Set PRS2 Register PR2=224' Set PR2 Resiger for 1ms timer2 GIE=1 PEIE=1 TMR2IE=1'Enable the Timer2 interrupt. TMR2ON=1' ' Defines for the SPI-Control Registers '------------------------------------------------------------------------------------- TRUE con 1; FALSE CON 0; CONT_WREN CON %00000110 'F-RAM WRITE ENBALE OP-CODE CONT_RDSR CON %00000101 'F-RAM READ STATUS REIGSTER OP-CODE CONT_WRSR CON %00000001 'F-RAM WRITE STATUS REGISTER OP-CODE CONT_READ CON %00000011 'F-RAM READ MOMEORY OP-CODE CONT_WRITE CON %00000010 'F-RAM WRITE MEMORY OP-CODE '------------------------------------------------------------------------------------- LOOP: '-------Write the OP-CODE and the three Bytes of address----- FM_CS=0 TX_BUff=cont_WREN gosub writespi fm_cs=1 fm_cs=0 tx_buff=cont_write gosub writespi '-----send three bytes of address------------- tx_buff=block0; gosub writespi tx_buff=add.byte1 gosub writespi tx_buff=add.byte0 gosub writespi '----------------------Write the first four bytes the desired data-------------- tx_buff=$02 gosub writespi tx_buff=$03 gosub writespi tx_buff=$04 gosub writespi tx_buff=$05 gosub writespi FM_CS=1 ADD=0 '----------------------Read the four bytes------------------------------------ fm_cs=0; tx_buff=cont_read gosub writespi '------------------Sending three byts of address--------------------------- tx_buff=block0; gosub writespi tx_buff=add.byte1 gosub writespi tx_buff=add.byte0 gosub writespi '-----------------Read data into the variables------------------------------- gosub readspi x1=rx_buff gosub readspi x2=rx_buff gosub readspi x3=rx_buff gosub readspi x4=rx_buff 'hserout [dec4 hour]; 'hserout [dec4 Minute]; 'hserout [dec4 Ticks]; 'hserout [hex ]; 'hserout [dec4 ]; 'hserout [dec4 ]; 'hserout [dec4 ]; IF Disp = 1 THEN LCDOUT $FE, 2 LCDOUT hex X1, ":",hex X2, ":",hex x3,":",dec4 Ticks PAUSE 20 ENDIF Disp = 0 'PAUSE 1000 GOTO LOOP '-----------------Sub routines for the SPI write and read----------------------- WriteSPI: WCOL=0 Rx_buff=SSPBUF ' CLEAR THE BUFFER SSPIF=0 ' CLEAR THE INTERRUP FLAG SSPBUF=tx_buff ' SEND THE BYTE IF(wcol) THEN RETURN WHILE(!SSPIF) WEND SSPIF=0; RETURN ReadSPI: rx_buff=SSPBUF ' Clear the buffer SSPIF=0 ' Clear the interrup flag SSPBUF=0 ' Shift out a dummy byte What is this? while(!sspif) ' wait for receive byte wend rx_buff=SSPBUF ' Get the byte return DISABLE ISR: 'pause 3 'pauseus 400 'TMR2ON=0' TURN OFF TMR2 Ticks = Ticks + 1 'IF Ticks < 4 THEN NoUpdate ' ' 1 second has elapsed, now update seconds and if necessary minutes and hours. ' if Ticks=1000 then ticks=0 Second = Second + 1 ' Update second IF Second = 60 THEN Second = 0 Minute = Minute + 1 ' Update Minute IF Minute = 60 THEN Minute = 0 Hour = Hour + 1 ' Update Hour IF Hour = 24 THEN Hour = 0 ENDIF ENDIF ENDIF endif Disp = 1 ' Set to update display ' ' End of time update ' NoUpdate: TMR2IF=0 ' Re-enable TMR2 interrupts Resume ENABLE ' Re-enable interrupts END END ' End of program
One Mbit? Now I have chip envy.
It looks like you need to add "FM_CS=1" right before the line "IF Disp = 1 THEN". The F-RAM never gets un-selected after the read.
It couldn't be that simple, could it? If that's not it please provide detail about what it is and is not doing correctly. If all else fails make sure it works using SHIFTIN and SHIFTOUT. If that fails as well use an o-scope to confirm ALL of the pins on the F-RAM are in their proper states.
Best Regards,
Paul
Actually I could use SHIFTIN and SHIFTOUT for accessing the F-RAM memory, as you told, it is a "comedy" wiring error, it seems like totally reversed. But for hardware SPI, I think the MISO,MOSI connection should be followed, right? In your code, it is connected like this.
Vinson
The only thing I don't like about SHIFTIN/SHIFTOUT is that they are so slow. But following advice from another thread (several threads actually) about SPI I used them to make sure everything was working in some fashion before I stepped up to the hardware SPI. Reversing the MISO/MOSI connections was just one of the many errors I started with. (I also spent an hour trying to figure out why I couldn't get *any* response from the F-RAM; turns out I hadn't actually installed the chip yet!)
Best Regards,
Paul
The fastest memory I know of would be SRAM parallel.
Just inc the PIC port in parallel with the SRAM to inc the memory address.
Fastest PIC interface is setting a port, faster than SPI etc.
Just search Digikey for SRAM then Parallel for ns transfer time memory.
Norm
As I found out the reads are all zeros, I use os-scope to track the signals and found out that there is totally no signals out in SCK, therefore no SDI because the master is not generating clocks. the SDO has some data out which I could not understand...So I am think if the MCU hardware got any problem.. or the MSSP module was not running?...it is really a torture...
.....
Vinson
Torture? If it were easy it wouldn't be nearly as much fun...
So no clock signals. SCK is on PORTC.3, which the datasheet says defaults to an input. You'll need to add "SCK_TRIS=0".
One other thing that jumped out at me is that the 16LF877 is only rated for 4MHz and you are using 10MHz according to your defines. Could that also be a source of trouble?
I hope you also took languer's suggestions. I'm pretty sure he's sharper than me...
Best Regards,
Paul
Bookmarks