Access MRAM via FT4222H USB-to-QSPI bridge
===
### 1. Download FT4222H Linux library and user guide
[libft4222-linux-1.4.4.44.tgz](https://www.ftdichip.com/Support/SoftwareExamples/libft4222-linux-1.4.4.44.tgz)
[User Guide for LibFT4222](https://www.ftdichip.com/Support/Documents/AppNotes/AN_329_User_Guide_for_LibFT4222.pdf)
### 2. Install library, compile sample code and test (source code ft4222_mram.c modified from spim.c)
Install libft4222
```bash=
mkdir libft4222
tar zxvf libft4222-linux-1.4.4.44.tgz -C libft4222
cd libft4222
sudo ./install4222.sh
```
Compile
```bash=
gcc ft4222_mram.c -o ft4222_mram -lft4222 -Wl,-rpath,/usr/local/lib
```
example code
```c=
#define CMD_READ 0x03
#define CMD_WRITE 0x02
#define MRAM_SIZE 0x100000
#define BUF_SIZE 0x100
static int mram_qpie(FT_HANDLE ftHandle)
{
FT4222_STATUS ftStatus;
int success = 1;
uint16 sizeTransferred;
uint16 bytesToTransceive;
uint16 bytesTransceived;
uint8 command[1] = {0x38};
uint8 response[4] = {0};
bytesToTransceive = 4;
ftStatus = FT4222_SPIMaster_SingleWrite(ftHandle, command, 1, &sizeTransferred, 1);
if((ftStatus!=FT4222_OK) || (sizeTransferred != 1))
{
success = 0;
goto exit;
}
printf("\nChange MRAM to QSPI mode.\n");
exit:
return success;
}
static int qspi_rdid(FT_HANDLE ftHandle)
{
FT4222_STATUS ftStatus;
int success = 1;
uint16 bytesToTransceive;
uint32 sizeOfRead;
uint8 command[1] = {0x9F};
uint8 response[4] = {0};
bytesToTransceive = 4;
ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, response, &command[0], 0, 1, bytesToTransceive, &sizeOfRead);
if((ftStatus!=FT4222_OK) || (sizeOfRead != bytesToTransceive))
{
success = 0;
goto exit;
}
printf("\nQSPI RDID:\n");
hexdump(response, 4);
exit:
return success;
}
static int qspi_rdsn(FT_HANDLE ftHandle)
{
FT4222_STATUS ftStatus;
int success = 1;
uint16 bytesToTransceive;
uint32 sizeOfRead;
uint8 command[1] = {0xC3};
uint8 response[8] = {0};
bytesToTransceive = 8;
ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, response, &command[0], 0, 1, bytesToTransceive, &sizeOfRead);
if((ftStatus!=FT4222_OK) || (sizeOfRead != bytesToTransceive))
{
success = 0;
goto exit;
}
printf("\nQSPI RDSN:\n");
hexdump(response, 8);
exit:
return success;
}
static int qspi_ruid(FT_HANDLE ftHandle)
{
FT4222_STATUS ftStatus;
int success = 1;
uint16 bytesToTransceive;
uint32 sizeOfRead;
uint8 command[1] = {0x4C};
uint8 response[8] = {0};
bytesToTransceive = 8;
ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, response, &command[0], 0, 1, bytesToTransceive, &sizeOfRead);
if((ftStatus!=FT4222_OK) || (sizeOfRead != bytesToTransceive))
{
success = 0;
goto exit;
}
printf("\nQSPI RUID:\n");
hexdump(response, 8);
exit:
return success;
}
#define BYTES_TO_WRITE (1024 * 1)
static int mram_qspi_write(FT_HANDLE ftHandle, int addr, char *buf, int len)
{
FT4222_STATUS ftStatus;
int success = 1;
uint32 sizeOfRead;
uint16 bytesToTransceive;
uint16 bytesTransceived;
uint8 command[BYTES_TO_WRITE + 4] = {0};
uint8 response[BYTES_TO_WRITE] = {0};
int i;
for (i = 0; i < len; i++) {
command[i + 4] = buf[i];
}
command[0] = CMD_WRITE;
command[1] = (addr >> 16) & 0xFF;
command[2] = (addr >> 8) & 0xFF;
command[3] = addr & 0xFF;
bytesToTransceive = BYTES_TO_WRITE;
ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, response, &command[0], 0, len + 4, 0, &sizeOfRead);
if((ftStatus!=FT4222_OK))
{
success = 0;
goto exit;
}
printf("\nwrite %d bytes\n", len);
exit:
return success;
}
static int mram_qspi_read(FT_HANDLE ftHandle, int addr, int len)
{
FT4222_STATUS ftStatus;
int success = 1;
uint32 sizeOfRead;
uint16 bytesToTransceive;
uint16 bytesTransceived;
uint8 command[4];
uint8 response[BYTES_TO_WRITE] = {0};
command[0] = CMD_READ;
command[1] = (addr >> 16) & 0xFF;
command[2] = (addr >> 8) & 0xFF;
command[3] = addr & 0xFF;
bytesToTransceive = len;
ftStatus = FT4222_SPIMaster_MultiReadWrite(ftHandle, response, &command[0], 0, 4, bytesToTransceive, &sizeOfRead);
if((ftStatus!=FT4222_OK) || (sizeOfRead != bytesToTransceive))
{
success = 0;
goto exit;
}
printf("\nRead %d bytes:\n", bytesToTransceive);
//hexdump(response, bytesToTransceive);
hex_dump(response, bytesToTransceive, 32, "RX");
exit:
return success;
}
```
Change clock rate `base clock = 60MHz`
```c=
typedef enum FT4222_SPIClock
{
CLK_NONE = 0,
CLK_DIV_2, // 1/2 System Clock
CLK_DIV_4, // 1/4 System Clock
CLK_DIV_8, // 1/8 System Clock
CLK_DIV_16, // 1/16 System Clock
CLK_DIV_32, // 1/32 System Clock
CLK_DIV_64, // 1/64 System Clock
CLK_DIV_128, // 1/128 System Clock
CLK_DIV_256, // 1/256 System Clock
CLK_DIV_512, // 1/512 System Clock
}
FT4222_SPIClock;
// Configure the FT4222 as an SPI Master.
ft4222Status = FT4222_SPIMaster_Init(
ftHandle,
SPI_IO_SINGLE, // 1 channel
CLK_DIV_4, // 60 MHz / 4 == 15 MHz
CLK_IDLE_LOW, // clock idles at logic 0
CLK_LEADING, // data captured on rising edge
SLAVE_SELECT(0)); // Use SS0O for slave-select
```
Enable MRAM QPIE before putting FT4222H to QSPI mode
```c=
mram_qpie(ftHandle);
ftStatus = FT4222_SPIMaster_SetLines(ftHandle,SPI_IO_QUAD);
if (FT_OK != ftStatus)
{
printf("set spi quad line failed!\n");
return 0;
}
```
Test
```bash=
sudo ./ft4222_mram 1
sudo ./ft4222_mram
```