This behaviour is really strange, because for the Rx to happen the Tx must work. Still, the data I write in the first loop doesn't end up in the SPI RAM. But data must be clocked in via Tx to retrieve the bytes, and I see data I wrote via standard polling to SPI before then.I tried a lot already but run out of ideas. Using spixbase or SPI1->DR doesn't make a difference; for both Tx and Rx or only the Tx DMA setup I end up with the same result.Enabling mem2mem bit makes the transfer not working at all (the idea was that this is the DMA software trigger which I need additionally to DMA_ENABLE according to the reference manual.) Also switching the spi_dma_tx() routine commands to enable spi_dma, then dma, then a while loop on SPI_BSY flag, then disabling spi_dma and dma doesn't deliver a good result, although the data shown changes to something like 0 0 2 0 0 1 0 0 0 ... randomly. This is also contradicting the idea to use the CPU while the data transfer takes place.I really want to manage using one of my STM32F103 dev boards with this project, although I already have a STM32F0-Disco and receive a STM32F407-Disco tomorrow.
Forums can be like that, it's not as if you're a huge contributor yourself. You are mixing polled/dma, not sure how well that will work. Pins look set up Ok as best I can tell. You could check as GPIO. Not sure how effective a disable/enable of DMA is for resetting address/count You use BRR BSRR in RMW fashion, really you don't need to do that, a simple write of the bits you're interested in is sufficient.
Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
I didn't mean to sound rude and impolite, I'm sorry. I thought it's a non-offending, non-swearing standard term in english (I'm no native speaker) which means ''Nobody has an idea?'' in more vivid language. Until now I was lurking in this forum, which was considered good style back in the last century on forums. I am active mostly in german forums as it is easier to help out in your native tongue and just started to post here (as I started looking at µCs only 8 weeks ago, first AVR, now Cortex/STM32, and struggle myself with STM32 I currently am not confident enough to be of help myself).I will rewrite the routines to use different buffer sizes and only use DMA transfer without polling, though I'm not sure this makes a difference - the polled Rx command with DMA after that and writing via polling still works. But maybe that is just a random effect?I also tried disabling/enabling SPI_I2S_DMA around the DMA enable/disable, that didn't change the result. I will try to write directly to the DMA registers to reset the address/counter. To be honest, I didn't reset the address until now at all; the results in the Rx buffer were pointing out that this seems unnecessary. But trying that is a good idea.I read that RMW is of course slower and not necessary, but I left it that way because I didn't consider the chip-select/deselect time critical and on other architectures it is necessary, so in a sense of readability it looked like the way to go. Will change that.Thank you again for giving some pointers where to go on!
Ok, tried the suggested changes to completely change to DMA without any polling.
uart_tx(
''Starting program.
''
);
// Check the RAM first
for
(
int
bank=0; bank<5; bank++) {
bool
is_ok=
true
;
chip_select(bank);
// Send WRITE MODE register command to chip
buffer1_tx[0]=WRMR;
buffer1_tx[1]=SEQUENTIAL_MODE;
spi1_dma_tx(2);
chip_deselect();
chip_select(bank);
// Send WRITE command to chip
buffer1_tx[0]=WRITE;
// as default sequential mode, thus address has to be sent only at start
buffer1_tx[1]=0;
//send even MoreMSByte address first
buffer1_tx[2]=0;
//send MSByte address first
buffer1_tx[3]=0;
//send LSByte address
spi1_dma_tx(4);
for
(
int
i=0; i<buffer_size; i++) {
buffer1_tx[i]=i;
buffer1_rx[i]=0;
}
for
(
int
i=0; i < (ram_size/buffer_size); i++) {
spi1_dma_tx(buffer_size);
}
chip_deselect();
chip_select(bank);
// Send WRITE MODE register command to chip
buffer1_tx[0]=WRMR;
buffer1_tx[1]=SEQUENTIAL_MODE;
spi1_dma_tx(2);
chip_deselect();
chip_select(bank);
// Send READ command to chip
buffer1_tx[0]=READ;
// as default sequential mode, thus address has to be sent only at start
buffer1_tx[1]=0;
//send even MoreMSByte address first
buffer1_tx[2]=0;
//send MSByte address first
buffer1_tx[3]=0;
//send LSByte address
spi1_dma_tx(4);
for
(
int
i=0; i<buffer_size; i++) {
buffer1_tx[i]=0xFF;
buffer1_rx[i]=0;
}
for
(
int
i=0; i < (ram_size/buffer_size); i++) {
spi1_dma_tx(buffer_size);
for
(
int
i=0; i<buffer_size; i++) {
if
(buffer1_rx[i] != i) is_ok=
false
;
}
}
sprintf(text,
''RAM chip %i is %s -> ''
, bank, (is_ok?
''OK.''
:
''not OK!''
));
uart_tx(text);
for
(
int
i=0; i<10; i++) {
sprintf(text,
''[%i] %i ''
, i, buffer1_rx[i]);
uart_tx(text);
}
uart_tx(
''
''
);
chip_deselect();
}
also resetting the base address of the transfer buffer; additionally tried to disable and enable SPI->DMA. I also tried using ''transfer size -1'' just in case, which doesn't change anything though.
The programm now immediatly stalls after
Starting program.
I even built a LED Cube yesterday just to have a little success with working with these cute µCs. _That_ works at least ;)
I'm still lost. What else could I try?
Edit: I just stumbled upon these App notes for STM32F0xx - how to use DMA:http://www.icbase.com/Promotion/download/AN4pdf
In that SPI example, they use TIM2 for generating a 4kHz PWM which is used as trigger for DMA. In the examples on the net I saw nothing like this. Is it necessary to use TIM2 to generate somehting like my SPI clock frequency for DMA to start? Or is that just misleading?
When the waiting-for-SPI-transfer-ready loop is removed, the program runs, even with starting the RAM check completely in DMA. The results are wrong though:
I added a global variable which is true during DMA transfers and gets set to false on the Transfer Complete interrupts. I use this for example in chip_select() and deselect() so the transfer has a chance to complete before I lift the CS pin. This is also checked before a new transfer gets started.
Interestingly, this doesn't help either; the result stays the same.
The DMA transfer looks alright, this is 0..1..2..3..4..5... and so on. Zooming into the MISO signal shows that the weird results I am seeing from the code are there on the line as well. I tried lowering the SPI frequency. With a Prescaler > 8, MISO stays calm all the time (constantly at HIGH level) until the polling code starts at the end.Maybe someone else had such a behaviour and could solve it?
If anybody is interested to the solution - it is quite simple: Wait for the damn transfer to finish before writing to the buffers again.
// Check the RAM first
for
(
int
bank=0; bank<5; bank++) {
bool
is_ok=
true
;
chip_select(bank);
// Send WRITE command to chip
buffer1_tx[0]=WRITE;
// as default sequential mode, thus address has to be sent only at start
buffer1_tx[1]=0;
//send even MoreMSByte address first
buffer1_tx[2]=0;
//send MSByte address first
buffer1_tx[3]=0;
//send LSByte address
spi1_dma_tx(4);
while
(transfer);
for
(
int
i=0; i<buffer_size; i++) {
buffer1_tx[i]=i;
buffer1_rx[i]=0;
}
for
(
int
i=0; i < (ram_size/buffer_size); i++) {
spi1_dma_tx(buffer_size);
}
chip_deselect();
chip_select(bank);
// Send READ command to chip
buffer1_tx[0]=READ;
// as default sequential mode, thus address has to be sent only at start
buffer1_tx[1]=0;
//send even MoreMSByte address first
buffer1_tx[2]=0;
//send MSByte address first
buffer1_tx[3]=0;
//send LSByte address
spi1_dma_tx(4);
while
(transfer);
for
(
int
i=0; i<buffer_size; i++) {
buffer1_tx[i]=0xff;
buffer1_rx[i]=0;
}
for
(
int
i=0; i < ((ram_size/buffer_size)); i++) {
spi1_dma_tx(buffer_size);
while
(transfer);
for
(
int
i=0; i<buffer_size; i++) {
if
(buffer1_rx[i] != i) {
is_ok=
false
;
sprintf(text,
''[%i]!=%i ''
, i, buffer1_rx[i]);
uart_tx(text);
}
}
}
sprintf(text,
''RAM chip %i is %s!
''
, bank, (is_ok?
''OK''
:
''NOT OK''
));
uart_tx(text);
chip_deselect();
}
At SPI_Prescaler_8 this results in 1 wrong byte in the last four chips.
Setting prescaler to 4 leads to this:
Starting program.
RAM chip 0 is OK!
RAM chip 1 is OK!
RAM chip 2 is OK!
RAM chip 3 is OK!
RAM chip 4 is OK!