cancel
Showing results for 
Search instead for 
Did you mean: 

SPI FRAM Data Issue

Muthaiah Murugappan
Associate II
Posted on July 13, 2018 at 01:05

Greetings,

I'm using Atollic True Studio compiler, cubemxcode with STM32L476RGx MCU. I'm trying to send and receive data to Memory FRAM MB85RS64V using SPI.Code below tries to send {0x06, 0x02, 0x00,0x04,0x01, 0x02, 0x03, 0x04, 0x04}, but the logic analyzer shows random garbage data everytime. (Screenshot Included)

int main(void)
{
 /* USER CODE BEGIN 1 */
 uint8_t writedata[] = {0x01, 0x02, 0x03, 0x04};
 uint8_t readata[4];
 GPIO_InitTypeDef gpioConfig;
 /* USER CODE END 1 */
 /* MCU Configuration----------------------------------------------------------*/
 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();
 /* USER CODE BEGIN Init */
 /* USER CODE END Init */
 /* Configure the system clock */
 SystemClock_Config();
 /* USER CODE BEGIN SysInit */
 /* USER CODE END SysInit */
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_SPI2_Init();
 /* USER CODE BEGIN 2 */
 gpioConfig.Pin= 12;
 gpioConfig.Mode = GPIO_MODE_AF_PP;
 gpioConfig.Pull = GPIO_NOPULL;
 gpioConfig.Speed = GPIO_SPEED_FREQ_MEDIUM ;
 gpioConfig.Alternate = 0;
 HAL_GPIO_Init(GPIOB, &gpioConfig);
 //for(int i=0;i<4;i++)
 HAL_SPI_TransmitReceive_IT(&hspi2, writedata, readata, sizeof(writedata)/sizeof(uint8_t));
 //HAL_SPI_Receive_IT(&hspi2, readata, sizeof(readata)/sizeof(uint8_t));
 //for(int i=0; i<50000; i++);
 //HAL_SPI_Receive_IT(&hspi2, read data, 1);
 //HAL_SPI_TransmitReceive(&hspi2, write data, read data, 1, HAL_MAX_DELAY);
 // FRAM Implementation
 uint8_t addr[]={0, 0x04};
 uint8_t opcodewrite[] = {0x02};
 uint8_t opcodewriteenable[]= {0x06};
 uint8_t opcodewritereset[]= {0x04};
 uint8_t opcoderead[] = {0x03};

 HAL_GPIO_WritePin(GPIOB, 12, 0);
 HAL_SPI_Transmit_IT(&hspi2, opcodewriteenable, sizeof(opcodewriteenable));
 HAL_SPI_Transmit_IT(&hspi2, opcodewrite, sizeof(opcodewrite));
 HAL_SPI_Transmit_IT(&hspi2, addr, 2);
 HAL_SPI_Transmit_IT(&hspi2, writedata, 4);
 HAL_SPI_Transmit_IT(&hspi2, opcodewritereset, sizeof(opcodewritereset));
 HAL_GPIO_WritePin(GPIOB, 12, 1);

 HAL_GPIO_WritePin(GPIOB, 12, 0);
 HAL_SPI_Transmit_IT(&hspi2, opcoderead, sizeof(opcoderead));
 HAL_SPI_Transmit_IT(&hspi2, addr, 2);
 HAL_SPI_Receive_IT(&hspi2, readata, 4);
 HAL_GPIO_WritePin(GPIOB, 12, 1);
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 
 
 /* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */
 }
 /* USER CODE END 3 */
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

0690X0000060QluQAE.png 0690X0000060QmBQAU.png 0690X0000060QlvQAE.png

I'm missing a small factor, which I don't get a tip-off, let me know your views on it ?! Thanks for your patience and time.

Muthaiah Murugappan

#stm32l476 #stm-32 #fram #hal-spi #stm-mcu
3 REPLIES 3
Andreas Bolsch
Lead II
Posted on July 13, 2018 at 23:53

Well, did you deliberately exclude the interesting part (i. e. SPI initialization)?

Probably PB12 is the CS pin for the FRAM? CS frames the individual commands, i. e. first pull CS low, send *ONE* command (with parameters like address, data where applicable), and then release CS. Then the same for the next command. Only the rising edge of CS triggers processing of the commands in the flash, FRAM, ...

If you send two commands without deactivating CS in between, you get ... garbage.

And: You're using the non-blocking Transmit_IT. This will return (almost) immediately, before the transmit is actually completed. And then you deactivate CS? This can't work at all. CS must be dactivated only after all bytes have been shifted out. So either you use automatic activation/deactivation of CS (aka hardware NSS), but then use of GPIO PB12 does not make sense. Or you use software NSS via the GPIO pin, but then you must wait until the data has been shifted out completely before you set CS to high.

Additionally some cosmetics: opcodewritereset (i.e. 'Write Disable') is not necessary at all. After a sucessfull write the write enable flag will be reset automatically. But it might be useful to verify after the 'Write Enable' the contents of the status register for the write enable flag being set. And checking the busy flag at the very beginning is a good idea anyway.

Muthaiah Murugappan
Associate II
Posted on July 16, 2018 at 15:02

Hey Andreas,

Thank you for your valuable time. Yes,I deliberatelyleft out the configuration steps. The second solution you provided of using the wait loop worked out to give MOSI the expected data.

If pseudo code might help:

#define ADD 0x04
uint8_t unused[4];
void Memory(void)
{
uint8_t writedata[] = { 0x01, 0x02, 0x03, 0x04};
uint8_t readdata[4];
GPIO_Config gpioConfig;
SPI_Config spiConfig;
 
// Configure Slave Select in GPIO
gpioConfig.pull = PULL_DOWN;
gpioConfig.mode = MODE_OUTPUT;
gpioConfig.op_type = OP_TYPE_PUSHPULL;
gpioConfig.speed = SPEED_MEDIUM;
InitializePort(NSS_PORT);
ConfigurePin(NSS_PORT, NSS_PIN, &gpioConfig, SPI_ALT_FUNCTION);
gpioConfig.mode = MODE_ALT;
gpioConfig.op_type = OP_TYPE_PUSHPULL;
gpioConfig.speed = SPEED_MEDIUM;
// Configure clock pin
gpioConfig.pull = ST_GPIO_PULL_DOWN;
InitializePort(CLK_PORT);
ConfigurePin(CLK_PORT, CLK_PIN, &gpioConfig, SPI_ALT_FUNCTION);
// Configure MISO pin
gpioConfig.pull = PULL_UP;
InitializePort(MISO_PORT);
ConfigurePin(MISO_PORT, MISO_PIN, &gpioConfig, SPI_ALT_FUNCTION);
// Configure MOSI pin
gpioConfig.pull = PULL_UP;
InitializePort(MOSI_PORT);
ConfigurePin(MOSI_PORT, MOSI_PIN, &gpioConfig, SPI_ALT_FUNCTION);
// Configure SPI
// Initialize the SPI peripheral.
spiConfig.baudRatePrescaler = PRESCALER_32;
spiConfig.biDirectional = true;
spiConfig.mode = MODE_1;
spiConfig.dataSize = DATASIZE_8;
spiConfig.lsbFirst = MSB_FIRST;
spiConfig.softwareSS = SW_SS;
spiConfig.master = true;
InitializeSPI(CHANNEL, &spiConfig);

WriteMemory( 1,writedata, sizeof(writedata) / sizeof(uint8_t));
//for(int i=0;i<500;++i);
ReadMemory( 1,readdata, sizeof(writedata) / sizeof(uint8_t));
}
void FramWrite(uint8_t addr, uint8_t *txbuffer, uint32_t size)
{
uint8_t opcode[] = {OPCODE_WRITE};
uint8_t opcode1[]= {OPCODE_WREN };
uint8_t opcode2[]= {OPCODE_WRDI };
uint8_t add[] = { 0, ADD};
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, opcode1, unused, sizeof(opcode));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, opcode, unused, sizeof(opcode));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, add, unused, sizeof(address));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
Transfer(1, txbuffer, unused, size);
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, opcode2, unused, sizeof(opcode));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
}
void FramRead(uint8_t addr, uint8_t *rxbuffer, uint32_t size)
{
uint8_t opcode[] = {OPCODE_READ};
uint8_t add[] = { 0, ADD};
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, opcode, unused, sizeof(opcode));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
SPI_Transfer(1, add, unused, sizeof(address));
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
WritePin(NSS_PORT, NSS_PIN, 0);
 SPI_Transfer(1, unused, rxbuffer, size);
while(IsBusy(CHANNEL));
WritePin(NSS_PORT, NSS_PIN, 1);
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

But my MISO gives me all 0xFF all the time. Trying to debug that, give me ideas from the screenshot below.0690X0000060QnnQAE.png

Thanks

Muthaiah

Posted on July 16, 2018 at 16:41

That's not going to work either: The falling edge of CS starts a new command, rising edge terminates it.

The datasheet of MB85RS64 has clear pictures how this works, e. g. for the write command:

1) set CS low

2) shift out write command

3) shift out address bytes

4) shift out data byte(s)

5) set CS high

CS must go high only after *ALL* bytes for the command (i. e. opcode, address, data) had been transferred!