azhel12 / Zhele

Framework for Stm32 MCU on C++ templates. Project based on "mcucpp" by Konstantin Chizhov.
BSD 2-Clause "Simplified" License
41 stars 9 forks source link

SPI class doesn't work. #23

Open NEOVIS78 opened 6 months ago

NEOVIS78 commented 6 months ago

SPI Functions (SendAsync, WriteAsync, WriteAsyncNoIncrement, ReadAsync) associated with dma do not work and freeze.

azhel12 commented 6 months ago

Thank you for report, does at least one byte (one chunk) of data transmitted/received? I have been remove all interrupt handlers include DMA from library for optimize binary code (no handler -> no template instance). So, you should add

void DMAx_IrqHandler() {
    DmaX::IRQHandler();
};
NEOVIS78 commented 6 months ago

Good afternoon. I'm using VisualGDB and Microsoft Visual Studio.

Yes, I have added an interrupt handler. As for the byte transfer, I'll come home tonight and check it out. In the old version it worked without problems.

max7219.zip

NEOVIS78 commented 6 months ago

The problem was with the optimization level -Os did not work -O1 worked. It worked strangely before.

azhel12 commented 6 months ago

Ok, ty for project archive, I'll build it and fix the bug!

azhel12 commented 6 months ago

I have tried build and run code in Proteus, it works. At least SPI commands are equal for code with/without DMA, for code with/without Os optmization.

Also I ordered max7219 module and repeat experiment later (on this weekends).

azhel12 commented 6 months ago

I reproduced problem. It's really no info on display with O1, Os, Og options.

I think that it is 2 reasons:

  1. For optimized build program work significantly faster.
  2. SPI Spi::Busy() method depend on BSY flag which should be cleared. It may occured when TXempty, not transmit complete!!!
  3. I tried replace waiting Spi::Busy() with waiting Dma::Transfer Complete(), but got same result. Its similar reason.

So, I fixed your code by insert small delay (1ms works) after SPI transfer:

  DevSPI::WriteAsync(spi data, maxbytes);
  while (DevSPI::Busy()) {};        
  delay_ms<1>(); // Delay

It's very very bad solution and I'll think about this case (it may be actual for i2c, uart, etc).

Sorry for this bug:(

UPD: other solution: fill whole display (allocate 2N bytes, fill it every second and send all in one transfer)

NEOVIS78 commented 6 months ago

Thank you. And this is also with the library for ili9341. I did something like this.

azhel12 commented 6 months ago

Cool! You can do pull request or allow me add your code (with you as author of course).

NEOVIS78 commented 6 months ago

Ok, no problem, I will make some improvements to the ili9341, ili9488 libraries.

NEOVIS78 commented 6 months ago

Good morning! For verification, I inserted functions into '\include\zhele\common\spi.h': `static bool ReadyDmaTx() { return !_DmaTx::Ready(); }

static bool ReadyDmaRx() { return !_DmaRx::Ready(); }`

Now it works like this:

Spi1::WriteAsyncNoIncrement(linebuff, len * 3, nullptr); while (Spi1::ReadyDmaTx()) ; while (Spi1::Busy());

azhel12 commented 6 months ago

Hello, good! In fact, it's not best practice to wait async (DMA) operation synchronously, but in this case its OK solution.

I recommend to add two writeX methods in your drivers: Write and WriteAsync to allow user choose.

NEOVIS78 commented 4 months ago

https://www.youtube.com/watch?v=mxci8V_RDbs for font arduino.

NEOVIS78 commented 4 months ago

ILI9488 I Will Make The Video a Little Later.

NEOVIS78 commented 4 months ago

https://www.youtube.com/watch?v=FPMEHmv5eXc ili9488

NEOVIS78 commented 4 months ago

[Uploading drivers.zip…]()

azhel12 commented 4 months ago

Uploading drivers.zip…

It's link on this issue:)