STM32 + SPI only work one cycle - Page 1
Forum section: electronics / general

author: grafi
author_rank: Contributor
timestamp: August 02, 2019, 08:49:26 am
content: Hi,I am working with a STM32L053C microcontroller and i want use an e-paper display. Actually i am using STM32cubeIDE and HAL.I have a problem with the display and the microcontroller. If i run the example display example code, all works fine. The problems start when i tried to put together all parts of my hardware. All works fine but the e-paper not. At the first cycle the e-paper works well but only works one time. Next cycles the e-paper not work as expected. Only show the last instructions that it was sent last cycle.Between cycles i have tried to disconnect the e-paper and connect again, but this not works.I saw with the osciloscope that the SPI commnications not work as the first time.I think the SPI comunicatión don´t work well after the first cycle.I tried to DeInit() the SPI after the first cycle and Init() the SPI on each cycle but not work.How can i restart the SPI port? Is it possible restart the SPI as whent the microcontroller start the first time?Could anyone said me some suggestions to resolve the problem?Thanks,Regards.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 02, 2019, 10:47:30 am
content: You can reset the SPI perihperal, but that won't fix your problem.SPI can't get stuck in state. It is either busy transmitting/receiving a word, or waiting for a word. It has a busy flag for this.But a poorly written driver can get out of sync with the display.Because it didn't wait for the display to process a command for example. The LCD will just ignore the next command, and you're out of sync.

author: grafi
author_rank: Contributor
timestamp: August 02, 2019, 11:08:44 am
content: Hi,Thanks for your response.I get the SPI state just before the init and always i get state_ready. In all cycles but not work the display:Code:if (EPD_Init(&epd, lut_full_update) != 0) {//printf("e-Paper init failed\n");HAL_UART_Transmit(&hlpuart1, "e-Paper init failed\r\n", strlen("e-Paper init failed\r\n"), 100);}uint8_t spi_estado = HAL_SPI_GetState(&hspi1);memset(uartBuf, '\0', sizeof(uartBuf));sprintf(uartBuf, "SPI estado: 0x%08X | %d\r\n", spi_estado, spi_estado);HAL_UART_Transmit(&hlpuart1, uartBuf, strlen(uartBuf), 100);In each cycle i power on and off the display.One time i have added next line into the e-paper library:Code:while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);and the spi send function looks like:Code:void EpdSpiTransferCallback(unsigned char data) {HAL_GPIO_WritePin((GPIO_TypeDef*)pins.port, pins.pin, GPIO_PIN_RESET);HAL_SPI_Transmit(&hspi1, &data, 1, 1000);while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);HAL_GPIO_WritePin((GPIO_TypeDef*)pins.port, pins.pin, GPIO_PIN_SET);}I am using this e-paper stm32 library:https://github.com/soonuse/epd-library-stm32/tree/master/1.54inch_e-paper/stm32If the SPI not work well, why the e-paper work onle the first cycle? Next while cycle not work and if i use the stop mode, when the microcontroller wake-up the e-paper not work.Thanks for your time,Regards.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 02, 2019, 01:07:03 pm
content: This is probably just a bad driver, or improper use of the driver. The driver expects the display to be in a certain state, which it isn't due to a previous command not being performed or being sent while busy.You can check with a logic analyzer if the SPI still sends stuff, which I'm sure it does.Verify if the display also has a busy bit, check this when waiting for it to do it's thing.Also verify that you're not going to a sleep mode that loses register and ram contents that you do not expect to lose.

author: thm_w
author_rank: Super Contributor
timestamp: August 02, 2019, 10:13:53 pm
content: Are you using a debugger (stlink) to see if you code is getting stuck somewhere or doing anything unexpected?Performing an SPI transfer *in* the SPI transfer complete callback doesn't seem right to me (I think thats what it is). Try updating every 500ms or something instead.edit: ignore its not the complete callbackhttps://github.com/soonuse/gdep015oc1_1.54inch_e-paper/blob/master/stm32/BSP/epdif.c

author: grafi
author_rank: Contributor
timestamp: August 04, 2019, 06:57:21 pm
content: Quote from: thm_w on August 02, 2019, 10:13:53 pmYes, i have used a stlink and i have checked if the code do some wrong. I am a begginer but i think that the code "working as expected" (i am not 100% sure).First while loop, i send some text and one QR code to show in the e-paper. I do some tasks with the e-paper without problems. First cycle (first while loop), all work as expected. Next whiles loop (using and not using the stop mode as low power mode), the e-paper only show the last screen sent in the last loop. When i send something to the e-paper, the display show the last screen sent in last loop. Next commands sent to the e-paper, the display don´t show anything, next command show the last screen sent in the first loop. The rest of the code work as expected.I don´t understood what do you want say here: Performing an SPI transfer *in* the SPI transfer complete callback doesn't seem right to me (I think thats what it is). Try updating every 500ms or something instead.Quote from: Jeroen3 on August 02, 2019, 01:07:03 pmI have not a logic analyzerI need buy one.If the SPI had a conflict, why i dont get the problems in the first loop?When the microcontroller wake-up, i do the init of SPI, but only work well at the first loop. I have tried with the stop mode and without the stop mode, but don´t work.The e-paper only have a 3 SPI pins (MOSI, CLK, CS) and other pins as reset, busy, vcc, gnd... Between loops i turn off the VCC e-paper, so the hardware should be how the first cycle.I am not sure about the library works well because if i disconnect the e-paper i dont get the init error.How i could reset the microcontroller SPI interface? (if this is possible). This is not a good solution but could be a temporary solution.Thanks,Regards.

author: rstofer
author_rank: Super Contributor
timestamp: August 04, 2019, 08:17:13 pm
content: I haven't played with STM32 SPI so feel free to ignore all of this:SPI packets are framed by CS' First, CS goes low, some data is transferred (the length in bytes is determined by the slave) and, AFTER the last byte is actually transferred and the SPI gadget changes state to Ready (or sends a completion interrupt), then CS is changed to high.The problem with most code is that it doesn't wait for the last byte to transfer before raising CS' and from then on, things go sideways. Perhaps the last byte of the previous transaction is now the first byte of the current transaction.I'm not going to go through the HAL code, that stuff is too grim to contemplate. I swear these libraries are created by doctors specializing in Carpel Tunnel surgery caused by the excessive typing. Never use 5 characters when an entire sentence will suffice!It appears that the code above actually waits for Ready but unless I read the datasheet and reviewed the library code, I would be wondering. Of course a logic analyzer is a great help and I actually bought the 4 channel Rigol DS1054Z scope for the specific purpose of decoding SPI transactions. Yes, it also does a lot of other really neat things!

author: grafi
author_rank: Contributor
timestamp: August 04, 2019, 08:48:37 pm
content: Quote from: rstofer on August 04, 2019, 08:17:13 pmMy oscilloscope is the DS1054Z. I don´t remember that it has an analyzer.One thing, if i turn off the e-paper VCC, the display should be initialized?Thanks,Regards.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 04, 2019, 08:57:30 pm
content: If you turn off Vcc from the display then you must also tell the library is should initialize the displayagain.Anyway, resetting SPI is easy. See RCC->APB2RSTR bit SPI1RST (bit 12), chapter 7.3.10 of the reference manual.The DS1054Z does have SPI protocol decoding as an option. This forum has topics about how to enable those protocol decoding options if it isn't enabled already.Quote from: grafi on August 04, 2019, 06:57:21 pmDoes the library know about this busy signal? Did you implement this correctly?

author: grafi
author_rank: Contributor
timestamp: August 04, 2019, 09:54:13 pm
content: Quote from: Jeroen3 on August 04, 2019, 08:57:30 pmI am not the writer of library, so i am not sure if the library works well. I think that the library use the busy signal. This is the library that i am using:https://github.com/soonuse/epd-library-stm32/tree/master/1.54inch_e-paper/stm32I initialize the library always. I will go to check my oscilloscope to debug the SPI protocol and check the SPI reset too.Thanks,Regards.

author: grafi
author_rank: Contributor
timestamp: August 05, 2019, 08:14:13 am
content: Hi,I test the SPI reset but dont works. I have added this lines (MX_SPI1_Init() is used in each loop before i use the e-paper):RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST; //reset SPI1RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST; //reset SPI1MX_SPI1_Init();I have checked the library to be sure about if the CS, BUSY and RST pins are been used, and the library use the pins.I will go to check the oscilloscope to see the logics.I am using too an ADC, TIM2, UART2, LPUART1 and RTC. Could be any interference between interfaces?Thanks,Regards.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 05, 2019, 08:18:22 am
content: Quote from: grafi on August 05, 2019, 08:14:13 amDid you also reset the library?Quote from: grafi on August 05, 2019, 08:14:13 amNo. There is only one chip I know of that had a failure like this. And it was bad. They didn't even release the batch, they all got marked engineering sample.

author: grafi
author_rank: Contributor
timestamp: August 05, 2019, 08:26:49 am
content: Yes.. i do this:Code:RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST; //reset SPI1RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST; //reset SPI1MX_SPI1_Init();HAL_Delay(1000);if (EPD_Init(&epd, lut_full_update) != 0) {HAL_UART_Transmit(&hlpuart1, "e-Paper init failed\r\n", strlen("e-Paper init failed\r\n"), 100);}Is it correct? or i need add this line:Code:EPD epd;Just before of:Code:if (EPD_Init(&epd, lut_full_update) != 0) {HAL_UART_Transmit(&hlpuart1, "e-Paper init failed\r\n", strlen("e-Paper init failed\r\n"), 100);}Maybe i am wrong, how can i reset the library?Thanks,Regards.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 05, 2019, 09:35:26 am
content: Looks like EPD_Init will do what you want. But resetting everything everytime you want to update the display is not how it is supposed to work.Go read the source code of the library. It's not that big. You'll figure it out.

author: grafi
author_rank: Contributor
timestamp: August 05, 2019, 12:52:03 pm
content: I think that i found the problem. Maybe the SPI wasn´t the problem. I am programming this line inside the e-paper function:Code:unsigned char* frame_buffer = (unsigned char*)malloc(EPD_WIDTH * EPD_HEIGHT / 8);and the only option is program this line in the main(). If i write this line in other place, the e-paper only works well in first loop.I don´t know why this happend. Could anyone tell me?Thanks all your time.Regards,

author: Jeroen3
author_rank: Super Contributor
timestamp: August 05, 2019, 02:25:48 pm
content: Malloc uses heap, do you have heap enabled and assigned?Does Malloc return a usable pointer and not NULL?Do you even need to use malloc, could you point to a static allocated aligned array of size (EPD_WIDTH * EPD_HEIGHT / 8 ).

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 05, 2019, 02:28:01 pm
content: Ouch.* Does the MCU even have enough RAM for this malloc?* Is malloc called only once or repeatedly without ever freeing memory?

author: grafi
author_rank: Contributor
timestamp: August 05, 2019, 02:38:24 pm
content: Quote from: SiliconWizard on August 05, 2019, 02:28:01 pmMy program use 65% of the RAM. When i compile the code, i don´t get any warning about space.If i don´t write in main(), the malloc is called one in each loop.Quote from: Jeroen3 on August 05, 2019, 02:25:48 pmIt is my first time that i use malloc. I have not enogh knowledge about this. I need learn more about it.Thanks,Regards.

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 05, 2019, 03:04:03 pm
content: Quote from: grafi on August 05, 2019, 02:38:24 pmIndicated RAM usage at compile time can't take dynamic allocations into account AFAIK. So infer that you only have 35% RAM left for your malloc().Quote from: grafi on August 05, 2019, 02:38:24 pmYou can't just keep allocating more memory without freeing some first. If you keep calling malloc in a loop without calling a corresponding free(), you'll be running out of memory in no time. That's called a memory leak.Just declare and use a static array instead.malloc should be used very cautiously in embedded code, doesn't seem to be justified here, and in any case, you should definitely learn how to use it before considering using it. Stick to static arrays for now.

author: rstofer
author_rank: Super Contributor
timestamp: August 05, 2019, 03:54:21 pm
content: Quote from: grafi on August 05, 2019, 02:38:24 pmAll you need to learn is to NEVER use dynamic allocation in embedded processors with limited RAM. My rule is to never use it at all!The GCC string functions use the heap therefore sprintf() and, by extension, printf() use the heap. In most cases, the programmer has to implement sbrk() (the allocator) and if you see sbrk() in the linker map, the heap is likely being used. For many libraries, sbrk() and some file functions are contained in syscalls.c. Get rid of it!Static allocation is the way to go because the data either fits in the memory or it doesn't but that is known at link time. With the stack growing down and the heap growing up, they sometimes collide.There are some lightweight versions of printf() that don't use the heap. I grab up my K&R "The C Programming Language" book and copy the various string functions into my own library. I don't get as far as printf() but I do have the basic functions and conversions like itoa() and atoi() so I'm pretty much set for debugging output.I avoid the heap at every opportunity!

author: Jeroen3
author_rank: Super Contributor
timestamp: August 05, 2019, 07:10:39 pm
content: When applied correctly dynamic memory can serve great purpose. Let's not lose ourselves in a discussion about the morality of dynamic memory on embedded systems.I think we've now pointed Grafi in the correct direction for a while.TryCode:unsigned char frame_buffer[(EPD_WIDTH * EPD_HEIGHT / 8)];

author: grafi
author_rank: Contributor
timestamp: August 05, 2019, 07:27:02 pm
content: Hi,Sorry i can reply before. I have check the option of static buffer (as Jeroen3 say) but i have not enogh RAM memory. The buffer needs 5000 bytes if i am not wrong. The microcontroller has 8kb o RAM and i comment some debug messages. Now i have 4.48kb of free memmory. If i use the malloc option, i can complile. The code works as expected for now. I will be watching the code for the next hours.Next time i will need to work with more RAM.Thanks for the comments, they are very usefull to the next steps.Regards,

author: Jeroen3
author_rank: Super Contributor
timestamp: August 06, 2019, 06:47:09 am
content: Malloc is also unable to allocate enough memory. The last bit of screen will be outside the SRAM. This may or may not create a fault.And then it makes sense it only works once, because the chip will be in the hardfault handler when it writes to the non-existing memory.Or worse, malloc does allocate memory, completely overwriting the other parts of your application.

author: richardman
author_rank: Frequent Contributor
timestamp: August 06, 2019, 07:17:16 pm
content: That's absolutely wrong with using malloc/free in embedded systems, if one knows what they are doing and is careful with what they are doing.

author: grafi
author_rank: Contributor
timestamp: August 08, 2019, 07:08:27 am
content: Quote from: Jeroen3 on August 06, 2019, 06:47:09 amFor now, all works well. I am not using all screen.Thanks all for your time.Regards,