USE of SPI bus with CS1
Posted: Thu Aug 02, 2018 10:40 pm
Here is some code to use the SPI port with CS1 I have tested it.
It was designed to work with a FM25V02A 32Kx8 FRAM memory which is simular to EE
The SPI port is very interesting it does chunks of DATA in 32 bytes max in the mode implemented here.
These functions loop until all the data is written/read so you can pass a large buffer to them.
The CS1 is driven for you, you do not need to worry about it.
/*******************************************************************************
* NAME: RWframVocore2
*
* COMPONENT HISTORY:
* Ver: User Date Action Description.
* --------- ---------- -----------------------------------
* 1.0 ArkEngr 05/31/2018 Created file
*
* Uses SPI with CS1, MOSI, MISO, CLK pins
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
typedef unsigned char USIGN8;
typedef unsigned short USIGN16;
typedef unsigned long USIGN32;
typedef unsigned int UINT;
typedef signed char INT8;
typedef signed short INT16;
typedef signed long INT32;
typedef char CHAR;
/* For use with FM25V02A 32Kx8 FerroElectric Memory */
#define PAGE_SIZE 4096
#define FRAM_WREN 6
#define FRAM_WRDIS 4
#define FRAM_RDSR 5
#define FRAM_WRSR 1
#define FRAM_READ 3
#define FRAM_WRITE 2
#define MEM_BASE 0x10000000
#define SPI_BUSY 0x00010000
#define SPI_START 0x00000100
#define SPI_MODE 0x0B28
#define SPI_MORE 0x0B2C
#define SPI_ADDR 0x0B04
#define SPI_CS1_ADDR 0x0B38
#define SPI_MST_ADDR 0x0B00
#define SPI_DIDO_0 0x0B08
#define SPI_DIDO_1 0x0B0C
#define SPI_DIDO_2 0x0B10
#define SPI_DIDO_3 0x0B14
#define SPI_DIDO_4 0x0B18
#define SPI_DIDO_5 0x0B1C
#define SPI_DIDO_6 0x0B20
#define SPI_DIDO_7 0x0B24
USIGN32 *mmap_page(void);
void fram_write(USIGN8 *ptr_src_dat, USIGN16 dest_adr, USIGN16 len);
void fram_read(USIGN16 src_adr, USIGN8 *ptr_dest, USIGN16 len);
void fram_byte_xchg(void);
USIGN32 *mem = NULL;
int main()
{
USIGN8 i, buffer[200];
printf("ver 1.0\n");
mem = mmap_page();
if(mem == NULL)
{
printf("can not map memory.\n");
return -1;
}
for(i = 0; i < 200; i++) /* fill with test data */
{
buffer[i] = i;
}
fram_write(buffer, 0, 200);
for(i = 0; i < 200; i++)
{
buffer[i] = 0xA5; /* fill with idiot data */
}
fram_read(0, buffer, 200);
for(i = 0; i < 200; i++) /* test */
{
printf("Addr: %4d, Data: %4d\n", i, buffer[i]);
}
munmap(mem, PAGE_SIZE);
}
USIGN32 *mmap_page(void)
{
INT32 fd = -1;
USIGN32 *fmem = NULL;
fd = open("/dev/mem", O_RDWR);
if(fd < 0)
{
return NULL;
}
fmem = (USIGN32 *)mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, MEM_BASE);
close(fd);
return fmem;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
Write a Data Block to FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_write(USIGN8 *ptr_src_dat, USIGN16 dest_adr, USIGN16 len)
{
USIGN16 i;
USIGN32 U8cmd, U8cmdCount, U16fram_addr, mosiCount, mosiBitCnt, ModeSave, ModeSet, WindowCnt;
// Wait until SPI not busy
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
usleep(100000); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
// Change clock speed
ModeSave = *((USIGN32 *)(mem + (SPI_MODE >> 2)));
ModeSet = 0x215E8984; // more_buf_mode = 1, half duplex
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSet;
WindowCnt = 0;
// loop until done
do
{
// Do Write Enable
U16fram_addr = FRAM_WREN;
U8cmdCount = 8; // bits in enable command
U8cmdCount = U8cmdCount << 24;
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
fram_byte_xchg(); // transfer the data
// Now Write Data
U8cmd = FRAM_WRITE;
U16fram_addr = U8cmd;
U16fram_addr = (U16fram_addr << 16) + dest_adr;
if(len >= 32)
{
mosiCount = 32;
len = len - 32;
}
else
{
mosiCount = len;
len = 0;
}
U8cmdCount = 24; // bits in write command
U8cmdCount = U8cmdCount << 24;
mosiBitCnt = mosiCount * 8; // Bits to write
U8cmdCount = U8cmdCount + mosiBitCnt; // Add outgoing msg len to command len
// Start FRAM Write
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
// printf("transfer data to regs\n");
// Load Dest with data
for(i = 0; i < mosiCount; i+=4)
{
*((((USIGN32 *)mem) + ((SPI_DIDO_0 + i) >> 2))) = *((USIGN32 *)(ptr_src_dat + i + WindowCnt)); // Write next data byte to FRAM
}
fram_byte_xchg(); // transfer the data
WindowCnt = WindowCnt + mosiCount;
dest_adr = dest_adr + mosiCount;
// End Loop
} while(len > 0);
usleep(10); // sleep for 100 milliseconds
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSave;
return;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
Read a Data Block from FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_read(USIGN16 src_adr, USIGN8 *ptr_dest, USIGN16 len)
{
USIGN16 i;
USIGN32 int_buff;
USIGN32 U8cmd, U8cmdCount, U16fram_addr, misoCount, misoBitCnt, ModeSave, ModeSet, WindowCnt;
// Wait until SPI not busy
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
usleep(100000); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
// Change clock speed
ModeSave = *((USIGN32 *)(mem + (SPI_MODE >> 2)));
ModeSet = 0x215E8984; // more_buf_mode = 1, half duplex
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSet;
U8cmd = FRAM_READ;
WindowCnt = 0;
// loop until done
do
{
U16fram_addr = U8cmd;
U16fram_addr = (U16fram_addr << 16) + src_adr;
if(len >= 32)
{
misoCount = 32;
len = len - 32;
}
else
{
misoCount = len;
len = 0;
}
U8cmdCount = 24; // bits in read command
U8cmdCount = U8cmdCount << 24;
misoBitCnt = misoCount * 8; // Bits to read
U8cmdCount = U8cmdCount + (misoBitCnt << 12); // Add outgoing msg len to command len
// Start FRAM Read
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
fram_byte_xchg(); // transfer the data
// printf("transfer data from regs\n");
// Load Dest with data
for(i = 0; i < misoCount; i+=4)
{
int_buff = *((((USIGN32 *)mem) + ((SPI_DIDO_0 + i) >> 2))); // Read next data byte from FRAM
*((USIGN8 *)(ptr_dest + i + WindowCnt)) = *(((USIGN8 *)&int_buff));
if((i + 1) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 1 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 1);
if((i + 2) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 2 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 2);
if((i + 3) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 3 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 3);
}
}
}
}
WindowCnt = WindowCnt + misoCount;
src_adr = src_adr + misoCount;
// End Loop
} while(len > 0);
usleep(10); // sleep for 100 milliseconds
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSave;
return;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
SPI Byte Transfer to or from FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_byte_xchg(void)
{
USIGN8 usval;
*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) = SPI_START; // Start data transfer
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
// printf("waiting on spi 0x%08X\n", *((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))));
usleep(10); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
return;
}
It was designed to work with a FM25V02A 32Kx8 FRAM memory which is simular to EE
The SPI port is very interesting it does chunks of DATA in 32 bytes max in the mode implemented here.
These functions loop until all the data is written/read so you can pass a large buffer to them.
The CS1 is driven for you, you do not need to worry about it.
/*******************************************************************************
* NAME: RWframVocore2
*
* COMPONENT HISTORY:
* Ver: User Date Action Description.
* --------- ---------- -----------------------------------
* 1.0 ArkEngr 05/31/2018 Created file
*
* Uses SPI with CS1, MOSI, MISO, CLK pins
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
typedef unsigned char USIGN8;
typedef unsigned short USIGN16;
typedef unsigned long USIGN32;
typedef unsigned int UINT;
typedef signed char INT8;
typedef signed short INT16;
typedef signed long INT32;
typedef char CHAR;
/* For use with FM25V02A 32Kx8 FerroElectric Memory */
#define PAGE_SIZE 4096
#define FRAM_WREN 6
#define FRAM_WRDIS 4
#define FRAM_RDSR 5
#define FRAM_WRSR 1
#define FRAM_READ 3
#define FRAM_WRITE 2
#define MEM_BASE 0x10000000
#define SPI_BUSY 0x00010000
#define SPI_START 0x00000100
#define SPI_MODE 0x0B28
#define SPI_MORE 0x0B2C
#define SPI_ADDR 0x0B04
#define SPI_CS1_ADDR 0x0B38
#define SPI_MST_ADDR 0x0B00
#define SPI_DIDO_0 0x0B08
#define SPI_DIDO_1 0x0B0C
#define SPI_DIDO_2 0x0B10
#define SPI_DIDO_3 0x0B14
#define SPI_DIDO_4 0x0B18
#define SPI_DIDO_5 0x0B1C
#define SPI_DIDO_6 0x0B20
#define SPI_DIDO_7 0x0B24
USIGN32 *mmap_page(void);
void fram_write(USIGN8 *ptr_src_dat, USIGN16 dest_adr, USIGN16 len);
void fram_read(USIGN16 src_adr, USIGN8 *ptr_dest, USIGN16 len);
void fram_byte_xchg(void);
USIGN32 *mem = NULL;
int main()
{
USIGN8 i, buffer[200];
printf("ver 1.0\n");
mem = mmap_page();
if(mem == NULL)
{
printf("can not map memory.\n");
return -1;
}
for(i = 0; i < 200; i++) /* fill with test data */
{
buffer[i] = i;
}
fram_write(buffer, 0, 200);
for(i = 0; i < 200; i++)
{
buffer[i] = 0xA5; /* fill with idiot data */
}
fram_read(0, buffer, 200);
for(i = 0; i < 200; i++) /* test */
{
printf("Addr: %4d, Data: %4d\n", i, buffer[i]);
}
munmap(mem, PAGE_SIZE);
}
USIGN32 *mmap_page(void)
{
INT32 fd = -1;
USIGN32 *fmem = NULL;
fd = open("/dev/mem", O_RDWR);
if(fd < 0)
{
return NULL;
}
fmem = (USIGN32 *)mmap(0, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, MEM_BASE);
close(fd);
return fmem;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
Write a Data Block to FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_write(USIGN8 *ptr_src_dat, USIGN16 dest_adr, USIGN16 len)
{
USIGN16 i;
USIGN32 U8cmd, U8cmdCount, U16fram_addr, mosiCount, mosiBitCnt, ModeSave, ModeSet, WindowCnt;
// Wait until SPI not busy
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
usleep(100000); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
// Change clock speed
ModeSave = *((USIGN32 *)(mem + (SPI_MODE >> 2)));
ModeSet = 0x215E8984; // more_buf_mode = 1, half duplex
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSet;
WindowCnt = 0;
// loop until done
do
{
// Do Write Enable
U16fram_addr = FRAM_WREN;
U8cmdCount = 8; // bits in enable command
U8cmdCount = U8cmdCount << 24;
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
fram_byte_xchg(); // transfer the data
// Now Write Data
U8cmd = FRAM_WRITE;
U16fram_addr = U8cmd;
U16fram_addr = (U16fram_addr << 16) + dest_adr;
if(len >= 32)
{
mosiCount = 32;
len = len - 32;
}
else
{
mosiCount = len;
len = 0;
}
U8cmdCount = 24; // bits in write command
U8cmdCount = U8cmdCount << 24;
mosiBitCnt = mosiCount * 8; // Bits to write
U8cmdCount = U8cmdCount + mosiBitCnt; // Add outgoing msg len to command len
// Start FRAM Write
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
// printf("transfer data to regs\n");
// Load Dest with data
for(i = 0; i < mosiCount; i+=4)
{
*((((USIGN32 *)mem) + ((SPI_DIDO_0 + i) >> 2))) = *((USIGN32 *)(ptr_src_dat + i + WindowCnt)); // Write next data byte to FRAM
}
fram_byte_xchg(); // transfer the data
WindowCnt = WindowCnt + mosiCount;
dest_adr = dest_adr + mosiCount;
// End Loop
} while(len > 0);
usleep(10); // sleep for 100 milliseconds
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSave;
return;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
Read a Data Block from FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_read(USIGN16 src_adr, USIGN8 *ptr_dest, USIGN16 len)
{
USIGN16 i;
USIGN32 int_buff;
USIGN32 U8cmd, U8cmdCount, U16fram_addr, misoCount, misoBitCnt, ModeSave, ModeSet, WindowCnt;
// Wait until SPI not busy
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
usleep(100000); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
// Change clock speed
ModeSave = *((USIGN32 *)(mem + (SPI_MODE >> 2)));
ModeSet = 0x215E8984; // more_buf_mode = 1, half duplex
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSet;
U8cmd = FRAM_READ;
WindowCnt = 0;
// loop until done
do
{
U16fram_addr = U8cmd;
U16fram_addr = (U16fram_addr << 16) + src_adr;
if(len >= 32)
{
misoCount = 32;
len = len - 32;
}
else
{
misoCount = len;
len = 0;
}
U8cmdCount = 24; // bits in read command
U8cmdCount = U8cmdCount << 24;
misoBitCnt = misoCount * 8; // Bits to read
U8cmdCount = U8cmdCount + (misoBitCnt << 12); // Add outgoing msg len to command len
// Start FRAM Read
*((USIGN32 *)(mem + (SPI_MORE >> 2))) = U8cmdCount; // 2C Command and Data len
*((USIGN32 *)(mem + (SPI_ADDR >> 2))) = U16fram_addr; // 04
fram_byte_xchg(); // transfer the data
// printf("transfer data from regs\n");
// Load Dest with data
for(i = 0; i < misoCount; i+=4)
{
int_buff = *((((USIGN32 *)mem) + ((SPI_DIDO_0 + i) >> 2))); // Read next data byte from FRAM
*((USIGN8 *)(ptr_dest + i + WindowCnt)) = *(((USIGN8 *)&int_buff));
if((i + 1) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 1 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 1);
if((i + 2) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 2 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 2);
if((i + 3) < misoCount)
{
*((USIGN8 *)(ptr_dest + i + 3 + WindowCnt)) = *(((USIGN8 *)&int_buff) + 3);
}
}
}
}
WindowCnt = WindowCnt + misoCount;
src_adr = src_adr + misoCount;
// End Loop
} while(len > 0);
usleep(10); // sleep for 100 milliseconds
*((USIGN32 *)(mem + (SPI_MODE >> 2))) = ModeSave;
return;
}
/*****************************************************************************
FUNCTIONAL_DESCRIPTION
SPI Byte Transfer to or from FRAM
RETURN_VALUE: none
*****************************************************************************/
void fram_byte_xchg(void)
{
USIGN8 usval;
*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) = SPI_START; // Start data transfer
while((*((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))) & SPI_BUSY) == SPI_BUSY)
{
// printf("waiting on spi 0x%08X\n", *((USIGN32 *)(mem + (SPI_MST_ADDR >> 2))));
usleep(10); // sleep for 100 milliseconds
} // Wait for SPI BUSY clear
return;
}