' Program: AT45Term.BAS written using PicBasicPro 3 ver 3.1.6.4 ' PicBasic Pro program to interface with an Atmel ATDBxxx DataFlash, ' 4mbit, 8mbit or 32mbit 8pin IC using the SPI protocol. ' Tested with: ' AT45DB041E (4 mbit) ' AT45DB081E (8 mbit) ' AT45DB321E (32 mbit) ' ' ALPHA CODE STILL IN DEVELOPMENT ' N O T F O R R E L E A S E ' ************* NOT FOR COMMERCIAL USE ************************* ' Ver. 0.6a Aug, 2022 (Original was July 2003) ' 'Last modified: Aug 28 2022 * Line 403 Changed a for/next loop to a varialble page size ' * Line 230 Changed counter ix to word var ' * Added Erase chip command and cleaned up some routines ' ' Proprietory Owner: COMPsys, Copyright 2022 ' ' Project Reference: AT45DB ' MCU: Microchip PIC16F877 20MHz OSC ' Software: Compiler PBPX V. 3.1.6.4, MicroCodePlus IDE ' PIC Programmer: Melabs USB programmer and the MCSP bootloader, ' Custom PCB with a serial interface ' for ISP and terminal output ' ' Initial Date: Jul 26, 2003 ' Projected Completion Date: Unknown ' ' Author: Ranjit Diol ' rsdiol@compsys1.com ' http://www.compsys1.com/workbench ' ' '*************************************************************** ' (c) COMPSys, 2003 ' All Rights Reserved '*************************************************************** '' DISCLAIMER: This file is being released as non-commericial ' software. It is being provided "AS IS", neither the author, ' nor COMPSys shall be held liable for any damages caused ' by its use. ' ' Contact: rsdiol@compsys1.com for more information ' '******************************************************************* ' Windows and DOS are registered trademarks of Microsoft Corporation '******************************************************************* ' 'Brief: The AT45DBxxx is a 2.7-3.6 volt part however the data lines, ' CS,SCK,WP are 5v tolerant ' One possible method of using the device in a 5v circuit would be ' to suplly Vcc through a voltage divider. ' Example: ' ' A couple of 5v to 3v conversion methods '======================================== 'Method 1: A 20 cent solution, but only if you have a hefty power source ' that can afford a drain strain! 'Parts: R1 100 ohm R2 200 ohm 1/4w resistors ' Vin(5v)----- 100 ohm R1 ' | ' -----------Vout 3.3v (no load) ' | this will fall within the ' 200 ohm R2 2.7-3.6v range of the AT45DB041 ' | The AT45DB041 requires 35ma max ' | during write/erase operations. Reading ' GND requires 10ma max. The typical currents ' are much less. ' 'Method 2: A 50 cent solution - much more elegant! ' Parts: ' IC1 LM317 ' R1 280 ohm R2 392 ohm (even a 390 will do) 1/8w resistors ' ' LM317 Top view 1=Adj 2=Out 3=In ' __ ' IC1 (___) ' 1 2 3----------- Vin (5v-20v) ' | | ' R1 between 1 & 2 280------------- 3v out ' | ' R2 between Gnd & 1 |____ 392_______ GND ' ' Another option is to use an LM1117 3.3 with a 10uf decoupling cap between Vout and GND ' ____ ' [___] LM1117 3.3 ' 1 2 3 ' Gnd| | | Vin (5-7v) ' 10uf | ' |_Vout (3.3v) ' ' AT45Dbxxx Data sheets available at http://www.atmel.com ' '============== Pin Connections ================ ' AT45DB041B ' PIC RB0 --> MOSI 1 8 MISO --> PIC RB1 ' PIC RB2 <-> SCK 2 7 Gnd --- Gnd ' Vcc --- /RST 3 6 Vcc --- Vcc ' PIC RB3 --> /CS 4 5 /WP --- Vcc ' '=============================================== ' AT45DB041 8pin SOIC pins: ' Pin1:MOSI ,Pin2:SCK,Pin3:/RESET,Pin4:/CS ' Pin5:/WP, Pin6:Vcc, Pin7:Gnd,Pin8:MISO ' PIC pins: ' Portb.0 MOSI,Portb.1 SDO,Portb.2 SCK, Portb.3 CS ' ' AT45DBxxx /WP (Pin5) and /RESET (pin3) are pulled high ' with a 4.7k resistor. ' ' Voltage: ' An LM3LM2937-3.3 is used to provide 3.3 volts ' a PIC16F876 can be used at 3.3v @ 10Mhz by disabling the PowerUpTimer ' ' ============ Memory Addressing ============== ' ' ' I M P O R T A N T ' PLEASE NOTES ' ************** Uncomment for a PIC16F876 operating on 3.3volts ************** '@ device pic16F876, xt_osc, wdt_on, pwrt_off, bod_off, lvp_off, cpd_off, wrt_off, protect_off ' ***************************************************************************** DEFINE LOADER_USED 1 'If using ISP DEFINE OSC 20 'Adjust to suit your design 'DEFINE OSC 10 'For an 16F876 running at 3.3v ADCON1 = 7 'Adjust ADC for your needs OPTION_REG.7=1 'Disable PORTB pull ups include "modedefs.bas" DEFINE DEBUG_REG PORTC 'Debug pin port DEFINE DEBUG_BIT 6 'Debug pin bit DEFINE DEBUG_BAUD 9600 'Debug baud rate DEFINE DEBUG_MODE 0 'Debug mode: 0 = True, 1 = Inverted DEFINE DEBUGIN_REG PORTC 'Debugin pin port DEFINE DEBUGIN_BIT 7 'Debugin pin bit DEFINE DEBUGIN_MODE 0 'Debugin mode: 0 = True, 1 = Inverted DEFINE HSER_BAUD 9600 'Hser baud rate DEFINE HSER_CLROERR 1 'Hser clear overflow automatically DEFINE HSER_SPBRG 129 'Hser spbrg init DEFINE HSER_RCSTA 90h 'Hser receive status init DEFINE HSER_TXSTA 24h 'Hser transmit status init high speed Symbol TXEN = TXSTA.5 'High= Enable transmit Symbol BRGH = TXSTA.2 'High=Select high baud rate Symbol SPEN = RCSTA.7 'High=Enable Serial Port Symbol CREN = RCSTA.4 'High=Enable continuous reception BRGH = 1 'High speed 'Constants,variables and aliases 'AT45DB041 instructions ATBuf1Wr con $84 'Buffer 1 write ATBuf2Wr con $87 'Buffer 2 write ATBuf1Rd con $54 'Buffer 1 read $54 *OBS* New $D4 Low frq $D1 ATBuf2Rd con $56 'Buffer 2 read $56 *OBS* New $D6 Low frq $D3 ATContRd con $68 'Continous array read $68 *OBS* New $0B Low Frq $03 Legacy $E8 ATPageRd con $52 'Main memory page read $52 *OBS* New $D2 ATStatRd con $57 'Status Read $57 *OBS* New $D7 ATB1PgEr con $83 'Buffer 1 to page with erase ATB2PgEr con $86 'Buffer 2 to page with erase ATB1PgNe con $88 'Buffer 1 to page with no erase ATB2PgNe con $89 'Buffer 2 to page with no erase ATPgEras con $81 'Page erase ATBkEras con $50 'Block erase ATPgBuf1 con $82 'Page program through buffer 1 ATPgBuf2 con $85 'Page program through buffer 2 ATPg2Bf1 con $53 'Page to buffer 1 transfer ATPg2Bf2 con $55 'Page to buffer 2 transfer ATPgB1cp con $60 'Page to buffer 1 compare ATPgB2cp con $61 'Page to buffer 2 compare ATPgRew1 con $58 'Auto page rewrite via buffer 1 ATPgRew2 con $59 'Auto page rewrite via buffer 2 'Other constants 'PageSz con 528 'BuffSz con 528 'PageCnt con 527 PageSz var word BuffSz var word PageCnt var word PageSz = 264 'Defaults sizes for 4 and 8 mbit chips BuffSz = 264 PageCnt =263 'AT45DB041 Connections MOSI var PORTB.0 ' AT45DB041 PIN 1 MISO var PORTB.1 ' AT45DB041 PIN 8 SCK var PORTB.2 ' AT45DB041 PIN 2 CS var PORTB.3 ' AT45DB041 PIN 4 TRISB.0 = 0 : TRISB.1 = 1 : TRISB.2=0 : TRISB.3=0 'Diagnostic LEDs wr_led var PORTB.7 err_led var PORTB.6 ok_led var PORTB.5 TRISB.7=0 : TRISB.6=0 : TRISB.5=0 'I2C Variables ctl con $A0 'EEPROM control code edata var BYTE 'Data byte to be written 'I2C Eeprom Pins scl var PORTC.3 'I2C SCL for ext eeprom sda var PORTC.4 'I2C SDA for ext eeprom 'Serial Pins out_pin var PORTC.6 'Serial OUT pin in_pin var PORTC.7 'Serial IN pin ser_baud con 84 '84=9600 32= 19200 Baud '***************** General Variables used ************************** 'Variables used (may be some that are no longer in use -- haven't cleaned up as yet!) page var word PageNum var word AT45sz var word addr var word adrs var word addr_H var word 'MMC Address is a 32 bit address, addr_h is bits 31-16 addr_L var word 'and addr_l is is bits 0-15 cmd var byte 'command var crc var byte 'crc var dat var byte 'data var i var byte 'counter var x var word 'counter var ix var word 'Changed to word from byte chr var byte len var word y var byte 'counter var res var byte 'response var stat var byte stat2 var byte 'Dataflash status w_lo var word w_hi var word w_rem var word w_res var word w_div var word arg1 var byte arg2 var byte arg3 var byte ErrFlag var byte TOcnt var byte buff var byte ATcmd var byte Opt var byte Opt2 var byte Wr_opt var byte pgszbit var byte pgsz var word Pages var word cntw var word cntw = 0 Pages = 0 Wr_opt = 0 'Status alias symbol ATstatus = stat.bit7 'Turn off diagnostic LEDs low wr_led : low ok_led : low err_led 'For debugging hserout ["AT45xxx Starting....",13,10] 'Initialize adrs=0 : cmd=0 : page=0 high cs 'Disassert AT45 cs line pause 200 'Let things settle gosub DummyRd 'May not be necessary in all cases ' ***** Jump over the subroutines ************** goto Main '********************* ' SUB-ROUTINES ' ******************** 'Subroutine that sends a command w/parameters 'Some commands require 1 or 4 no-care bytes after the command SendCmd: gosub CalcBits 'Calculate the 24 bits low cs SHIFTOUT MOSI,SCK,MSBFIRST,[cmd\8,page\16,addr\8] Select Case cmd Case ATPageRd,ATContRd '$52,$68 shiftout MOSI,SCK,MSBFIRST,[0\16,0\16] '4 byte no-care Case ATBuf1Rd,ATBuf2Rd '$54,$56 shiftout MOSI,SCK,MSBFIRST,[0\8] '1 byte no-care end select return 'Calculate Page & Addr address based on a linear address CalcAddr: disable R0 = addr_H R2 = addr_L PageNum = DIV32 PageSz Adrs = R2 enable return 'Calculate the 24 bits to be sent to the AT45DBxxx given Page & Addr CalcBits: page=page << 1 page.bit0 = addr.bit8 addr = addr.byte0 return 'Subroutine for busy signal 'It will "time-out" after 256 attempts CheckReady: TOcnt=0 : ErrFlag=0 low cs Shiftout MOSI,SCK,MSBFIRST,[ATStatRd] '$57 ATbusy: Shiftin MISO,SCK,MSBPOST,[stat,stat2] ' hserout ["Stat:",bin8 stat,"Stat2:",bin8 stat2,13,10] 'debug TOcnt=TOcnt-1: if TOCnt=0 then ATErr1 if ATstatus=0 then ATbusy goto NotBusy ATErr1: hserout ["AT45DBxxx Busy Error!",13,10] high Err_Led ErrFlag=1 'Set the ErrFlag NotBusy: high cs return 'Routine to simple cycle the AT45 IC DummyRd: high cs cmd=ATPageRd ' $52 read page direct command page=0 : addr=0 gosub SendCmd for ix=0 to 31 ' read some bytes shiftin MISO,SCK,MSBPOST,[chr\8] next ix high cs return 'Routine to calculate the size of the dataflash (512kb to 64mb) GetSize: Pages = 0 'initialize page count gosub CheckReady 'Get AT45DB status, bits 2-5 contain size info AT45sz=stat & %00111100 'Mask bits 2-5 pgszbit = stat & %00000001 'mask bit 1 AT45sz=AT45sz>>2 'Dispose of the beginning 2 zeroes if AT45sz=0 then hserout ["DataFlash Size=512kbit",13,10] : goto SzDone 'i=1: At45Sz=At45Sz-1 'i=i< 127 then chr="." if chr < 32 then chr="." hserout [chr] next ix high CS hserout [13,10] hserout ["More? 1=yes 2=no",13,10] hserin [dec1 chr] if chr<>1 then InData PageNum=PageNum+1 goto DataRead goto InData DataWrite: cntw=0 hserout ["Enter text ~ (tilde) to end",13,10] 'Write data to one of the two buffers cmd=ATBuf1Wr '$84 write to buffer 1 command addr=adrs 'Start address in the buffer gosub SendCmd hserout ["Addr:",dec adrs,13,10] Get_Key: hserin 1000,Get_Key,[chr] if chr <32 OR chr > 127 then Get_key if chr = "~" then Wr_Done shiftout MOSI,SCK,MSBFIRST,[chr\8] ' put it in the AT45DBxxx buffer 'Check if new page is required ' cntw=cntw+1 ' if cntw = PageSz then ' high cs 'close the buffer ' hserout ["Next page...",13,10] 'Add new page 'Write data to the new address ' cmd=ATB1PgEr ' adrs=adrs+PageSz ' hserout ["Addr2:",dec adrs,13,10] ' addr=adrs 'Start address in the buffer ' gosub SendCmd ' cntw=0 ' high cs 'endif goto Get_Key Wr_Done: high cs 'Write the buffer if Opt = 2 then cmd=ATB1PgEr 'Erase page and then write the buffer to the page if Opt = 3 then cmd=ATB1PgNe 'No erase and write **Not working correctly** page=PageNum gosub SendCmd high cs gosub CheckReady 'Check if AT45 is busy high cs goto InData AT_Test: 'PageNum=512 'Page number 'adrs=0 'Address on that page 0-264 for the AT45DB041B 'Given: Address = 270336 = $00042000 the result should be PageNum= 1024 Adrs=0 'addr_H = 0 '$0004 'addr_L = 0 '$2000 hserout ["Writing sample text to Buffer 1:",dec PageNum, " at Address:",dec adrs,13,10] 'goto ATRead 'Just read, no writing is done 'Write data to one of the two buffers cmd=ATBuf1Wr '$84 write to buffer 1 command addr=adrs 'Start address in the buffer gosub SendCmd len = 62 for ix=0 to len 'Message length in bytes lookup ix,["Welcome! This is an Atmel AT45DB0xxx mbit dataflash 8 pin chip!"],chr shiftout MOSI,SCK,MSBFIRST,[chr\8] ' put it in the AT45D0xx buffer hserout [chr] next ix high cs hserout [13,10] 'Read back the data from the buffer hserout ["Reading back buffer...",13,10] cmd=ATBuf1Rd '$54 read from buffer 1 command addr=adrs 'Start address in the buffer gosub SendCmd for ix=0 to len 'message length in bytes shiftin MISO,SCK,MSBPOST,[chr] ' get it from the AT45D0xx buffer hserout [chr] next high cs hserout [13,10] hserout ["Erase & write to DataFlash sector...",13,10] '------------------------------------------------ 'Erase page and then write the buffer to the page cmd=ATB1PgEr ' $83 erase page and write command page=PageNum gosub SendCmd 'Write buffer to AT45DBxxx high cs gosub CheckReady 'Check if AT45 is busy high cs ATRead: hserout ["Reading back DataFlash sector...",13,10] 'Read data directly from a page cmd=ATPageRd '$52 read page direct command page=PageNum addr=adrs gosub SendCmd 'Read data for ix=0 to len 'message length in bytes shiftin MISO,SCK,MSBPOST,[chr\8] hserout [chr] next ix high CS hserout [13,10] hserout ["Finished",13,10] goto InData 'Erase page PageErase: return 'Erase Block BlockErase: return 'Erase chip ATerase: hserout ["Are you ABSOLUTELY sure? 1=yes 2=no",13,10] hserout ["This may take 30 to 80 seconds",13,10] hserin [dec1 chr] 'DEC1 reads one decimal char if chr = 2 then ERabort hserout ["Erasing...",13,10] low cs SHIFTOUT MOSI,SCK,MSBFIRST,[$C7\8,$94\8,$80\8,$9A\8] 'Erase command high cs pauseus 10 'gosub checkready low cs Shiftout MOSI,SCK,MSBFIRST,[$57\8] '$57 Eead Status bytes {2} ATbusy2: Shiftin MISO,SCK,MSBPOST,[stat\8,stat2\8] ' hserout ["Stat:",bin8 stat,"Stat2:", bin8 stat2,13,10] 'debug hserout ["."] if stat.bit7 = 0 then ATbusy2 high cs hserout ["Erased!",13,10] ERabort: goto inData LoopEnd: goto LoopEnd 'Do nothing if you get here end '=================== END OF CODE =============================