Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with libopencm3, SPI and STM32l100rc #20

Open
krish2487 opened this issue Sep 16, 2019 · 0 comments
Open

Issue with libopencm3, SPI and STM32l100rc #20

krish2487 opened this issue Sep 16, 2019 · 0 comments

Comments

@krish2487
Copy link

Hello,

I seem to have a peculiar issue with the SPI peripheral on stm32L100. For information, I am using a STM32l100RC discovery board. I am trying to interface a SPI Flash module, specifically the W25Q64.

I am working off from the beginning STM32, libopencm3 freertos by warren gay. I am not using the example code per say, just trying to get my hands dirty by using parts of his code to test that the device actually works and I am able to read/write to it. I am just using the barebones spi flash routines he has provided in the repo here

https://github.com/ve3wwg/stm32f103c8t6

I am trying to read the JEDEC ID of the flash module. The flash module is supposed to return
the manufacturer ID, memory type and capacity in that order, specifically the bytes EF, 40, 17 hex. I did verify that the modules work by trying them out with a arduino uno and here is the screenshot of the logic analyzer capture from the uno's capture
64926866-16c4ab80-d803-11e9-91c2-efe8cedd4477

I tried to read the ID using the stm32l100rc discovery board and found that I am not able to get to the section where the command for reading the JEDEC ID is sent on the bus.
The code just is stuck in the w25_wait section.
Here is the screenshot of the same
64926892-95b9e400-d803-11e9-8731-c981e5e374c4
64926893-9a7e9800-d803-11e9-99e2-ae7764047918

The code is just stuck in the wait routine.

Here is the relevant code

#include "libopencm3/stm32/rcc.h"
#include "libopencm3/stm32/gpio.h"
#include "libopencm3/stm32/usart.h"
#include "libopencm3/stm32/spi.h"
#include "delay.h"

#define W25_CMD_MANUF_DEVICE	0x90
#define W25_CMD_JEDEC_ID	0x9F
#define W25_CMD_WRITE_EN	0x06
#define W25_CMD_WRITE_DI	0x04
#define W25_CMD_READ_SR1	0x05
#define W25_CMD_READ_SR2	0x35
#define W25_CMD_CHIP_ERASE	0xC7
#define W25_CMD_READ_DATA	0x03
#define W25_CMD_FAST_READ	0x0B
#define W25_CMD_WRITE_DATA	0x02
#define W25_CMD_READ_UID	0x4B
#define W25_CMD_PWR_ON		0xAB
#define W25_CMD_PWR_OFF		0xB9
#define W25_CMD_ERA_SECTOR	0x20
#define W25_CMD_ERA_32K		0x52
#define W25_CMD_ERA_64K		0xD8

#define DUMMY			0x00

#define W25_SR1_BUSY		0x01
#define W25_SR1_WEL		0x02

static const char *cap[3] = {
	"W25X16",	// 14
	"W25X32",	// 15
	"W25X64"	// 16
};	

static uint8_t
w25_read_sr1(uint32_t spi) {
	uint8_t sr1;

	spi_enable(spi);
	spi_xfer(spi,W25_CMD_READ_SR1);
	sr1 = spi_xfer(spi,DUMMY);
	spi_disable(spi);
	return sr1;
}

static uint8_t
w25_read_sr2(uint32_t spi) {
	uint8_t sr1;

	spi_enable(spi);
	spi_xfer(spi,W25_CMD_READ_SR2);
	sr1 = spi_xfer(spi,DUMMY);
	spi_disable(spi);
	return sr1;
}

static void
w25_wait(uint32_t spi) {
	uint8_t res= w25_read_sr1(spi);

	while ( (res & W25_SR1_BUSY) )
	{
		delay_ms(50);
		res = w25_read_sr1(spi);
	}
}

static uint16_t
w25_manuf_device(uint32_t spi) {
	uint16_t info;

	w25_wait(spi);
	spi_enable(spi);
	spi_xfer(spi,W25_CMD_MANUF_DEVICE);	// Byte 1
	spi_xfer(spi,DUMMY);			// Dummy1 (2)
	spi_xfer(spi,DUMMY);			// Dummy2 (3)
	spi_xfer(spi,0x00);			// Byte 4
	info = spi_xfer(spi,DUMMY) << 8;	// Byte 5
	info |= spi_xfer(spi,DUMMY);		// Byte 6
	spi_disable(spi);
	return info;
}

static uint32_t
w25_JEDEC_ID(uint32_t spi) {
	uint32_t info;

	w25_wait(spi);
	spi_enable(spi);
	spi_xfer(spi,W25_CMD_JEDEC_ID);
	info = spi_xfer(spi,DUMMY);		 // Manuf.
	info = (info << 8) | spi_xfer(spi,DUMMY);// Memory Type
	info = (info << 8) | spi_xfer(spi,DUMMY);// Capacity
	spi_disable(spi);

	return info;
}

static void
w25_read_uid(uint32_t spi,void *buf,uint16_t bytes) {
	uint8_t *udata = (uint8_t*)buf;

	if ( bytes > 8 )
		bytes = 8;
	else if ( bytes <= 0 )
		return;

	w25_wait(spi);
	spi_enable(spi);
	spi_xfer(spi,W25_CMD_READ_UID);
	for ( uint8_t ux=0; ux<4; ++ux )
		spi_xfer(spi,DUMMY);
	for ( uint8_t ux=0; ux<bytes; ++ux )
		udata[ux] = spi_xfer(spi,DUMMY);
	spi_disable(spi);
}


int main(void) {
	char array[] = "Hello World!!";
//Always set the clock for the ports and peripherals first

//Select HSICLK with PLL as sysclock source
// Sysclock frequency is 16 Mhz

	rcc_clock_setup_hsi(&rcc_clock_config[RCC_CLOCK_VRANGE1_HSI_RAW_16MHZ]);

//Enable GPIOC Peripheral clock
	rcc_periph_clock_enable(RCC_GPIOC);
//Output mode, no pull ups or pull down
	gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8 | GPIO9);
//Set GPIO8 and clear GPIO9 to see toggle
	gpio_set(GPIOC, GPIO8);
	gpio_clear(GPIOC, GPIO9);

//Sequence of steps for SPI transactions
//Enable the clocks for the pin ports and peripheral for SPI
//Setup pins for the alternate functions
//PA4 = SPI1_NSS, PA5 = SPI1_SCK, PA6 = SPI1_MISO, PA7 = SPI1_MOSI
//reset the SPI peripheral
//initialize the SPI peripheral with the peripheral, clock, clock polarity,
//clock phase, data frame format, frame format
//set nss management to software otherwise SPI peripheral wont work
//enable the SPI peripheral
//send or read data using spi_send or spi_read functions

	rcc_periph_clock_enable(RCC_GPIOA);
	rcc_periph_clock_enable(RCC_SPI1);
	gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO4 | GPIO5 | GPIO7);
	gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6);
	gpio_set_af(GPIOA, GPIO_AF5, GPIO4 | GPIO5 | GPIO7);
	gpio_set_af(GPIOA, GPIO_AF5, GPIO6);
	spi_reset(SPI1);
	spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);

	spi_disable_software_slave_management(SPI1);
	spi_enable_ss_output(SPI1);
	while (1)
	{
		gpio_toggle(GPIOC, GPIO8 | GPIO9);
		uint8_t index = 0;

		w25_wait(SPI1);
		spi_xfer(SPI1, 0x9F);
	 	uint8_t result1 = spi_xfer(SPI1, 0x00);
		uint8_t result2 = spi_xfer(SPI1, 0x00);
		uint8_t result3 = spi_xfer(SPI1, 0x00);
		spi_disable(SPI1);
		delay_ms(500);
	}

	return 0;
}

I apologize for the length of the code.
As I ve said earlier, the code is simply stuck in the w25_wait routine. it never progressess beyond.

I tried debugging further and it looks like that the condition
(res & W25_SR1_BUSY)
in the w25_wait function always returns true. This is because the previous function invocation of
uint8_t res= w25_read_sr1(spi);
in the line above always returns 1.
And this is the relevant snipper for the w25_read_sr1

w25_read_sr1(uint32_t spi) {
	uint8_t sr1;

	spi_enable(spi);
	spi_xfer(spi,W25_CMD_READ_SR1);
	sr1 = spi_xfer(spi,DUMMY);
	spi_disable(spi);
	return sr1;
}

But the logic analyzer capture shows that the data being returned is 0x00 not 0x01.

I would be extremely grateful if you can help me identify the issue to where and what I am doing wrong.
I am more inclined to believe it is because I goofed up something in the initialization and/or the handling. But it is more or less a adapted version of the book's example code from the bluepill to the stm32l100rc.

Thank you in advance.!! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant