2019-12-28 08:22 PM
SOLVED - look at edit below!
I am trying to implement SPI on nucleoH745ZI-Q without HAL or any kind of driver, I wrote my own registers pointers and functions like digitalWrite, pinMode or printf. I set up RCC, GPIO and SPI registers (all set, checked with debugger). But I can't get it work. I tried non-interrupt method (sending all data in loop - commented section) - with no luck. Then I tried interrupt method, I literally copied config from STM32CubeH7 Examples (checked registers with debugger and put it in my code), with no luck again. Always there is no sign of life on lines.
What am I doing bad?
Q&A:
main.c
int main(void) {
initClock(); // 480MHz / 240MHz
initSPI();
/* Infinite loop */
while (1) ;
}
void SPI(void) {
if(SPI1->SR != 2) printf("%x\n\r", SPI1->SR); // Debug
if(SPI1->SR & 2) SPI1->TXDR = 'abcd'; // Write data to FIFO if there's place
if(SPI1->SR & 8) SPI1->IER &= ~2; // End of Transmission - disable TXP interrupt
}
uint32_t (* const vector_table[])
__attribute__ ((section(".vectors"))) = {
(uint32_t *) 0x20020000, // 0x000 Stack Pointer
(uint32_t *) main, // 0x004 Reset
(uint32_t *) hardFault, // 0x008 Non maskable interrupt
...
(uint32_t *) SPI, // 0x0CC SPI1
...
}
spi.c
void initSPI() {
/**** GPIO ****/
pinMode(A4, ALTERNATE);
pinMode(A5, ALTERNATE);
pinMode(A6, ALTERNATE);
pinMode(B5, ALTERNATE);
PORTA->AFRL |= 0x5550000;
PORTB->AFRL |= 0x500000;
PORTA->OSPEEDR |= 0x3F00;
PORTB->OSPEEDR |= 0xC00;
RCC->APB2ENR |= (1 << 12); // Enable SPI clock
SPI1->CFG1 = 0x60000007; // MBR = 128 (375kHZ), 8-bits frame size
SPI1->CFG2 = 0xA4400000; // AFControl, SSO Enable, Software SS, Master mode
SPI1->CRCPOLY = 0x107; // CRC Polynomial
SPI1->CR2 = 8; // Data size (8 bytes = 8 frames by 8 bits)
SPI1->IFCR = (1 << 9); // Mask Mode Fault (why it's showing up?)
enableIRQ(35); // Enable SPI Interrupt
SPI1->IER = 0x76F; // Enable Interrupts
SPI1->CR1 = (1 << 12); // SS Enable
SPI1->CR1 |= 1; // Enable SPI
SPI1->CR1 |= (1 << 9); // CSTART - Start transmission
/**** Non Interrupt - tried, not worked ****/
//delay(50);
//
//int a[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
//int i = 0;
//while(i < 8) {
// if(SPI1->SR & 2) {
// *(uint8_t *)SPI1->TXDR = a[i++];
// printf("%x\n\r", SPI1->SR);
// }
//}
}
Analyzer Capture
EDIT:
Finally i was able to get it work. First of all On my lovely nucleo board SPI_CS are marked incorrectly (PD14 instead of PA4) so there was first mstake. What i've done is I rewrote all configuration from scratch and then it worked. I think that error was accessing TXDR by 8bit - 32bits works now. I changed also Frame size. Anyway There is part of my new code fell free to use it if You like.
spi.c
void initSPI() {
/**** GPIO ****/
pinMode(A4, ALTERNATE);
pinMode(A5, ALTERNATE);
pinMode(A6, ALTERNATE);
pinMode(B5, ALTERNATE);
PORTA->AFRL |= 0x5550000;
PORTB->AFRL |= 0x500000;
PORTA->OSPEEDR |= 0x3F00;
PORTB->OSPEEDR |= 0xC00;
RCC->APB2ENR |= (1 << 12); // Enable SPI clock
SPI1->CFG1 = 0x60070067; // MBR = 128 (375kHZ), 8-bits crc, 8-bits frame size, 4 frames packet size
SPI1->CFG2 = 0x34400000; // SSO Active High, SSO Enable, Software SS, Master mode
SPI1->CR2 = 8; // Data size (8 bytes = 8 frames by 8 bits)
enableIRQ(35); // Enable SPI Interrupt
SPI1->IER = 0x76F; // Enable Interrupts
SPI1->CR1 = (1 << 12) | 1; // Enable SS & SPI
SPI1->CR1 |= (1 << 9); // CSTART - Start transmission
/**** Non Interrupt ****/
/*int i = 0;
while(i < 8) {
if(SPI1->SR & 2) {
if(i++ % 2 == 0) SPI1->TXDR = 0xAAAAAAAA;
else SPI1->TXDR = 0x55555555;
printf("%x %x\n\r", SPI1->SR, SPI1->CR1);
}
if(SPI1->SR & 8) {
printf("done");
SPI1->CR1 &= ~(1 << 12);
break;
}
}*/
}
main.c
int main(void) {
initClock(); // 480MHz / 240MHz
initSPI();
while(1);
}
void SPI(void) {
if(SPI1->SR & 2) SPI1->TXDR = 'elo!'; // Write data to FIFO if there's place
if(SPI1->SR & 8) {
printf("done");
SPI1->IFCR = 0xFF8; // Reset SR
SPI1->IER = ~2; // End of Transmission - disable TXP Interrupt
SPI1->CR1 &= ~(1 << 12); // Disable NSS
}
}
uint32_t (* const vector_table[])
__attribute__ ((section(".vectors"))) = {
(uint32_t *) 0x20020000, // 0x000 Stack Pointer
(uint32_t *) main, // 0x004 Reset
(uint32_t *) hardFault, // 0x008 Non maskable interrupt
...
(uint32_t *) SPI, // 0x0CC SPI1
...
}
Analyzer Capture:
2019-12-28 11:38 PM
H7 complexity is higher than most other STM32, so try to run a modified example of HAL Nucleo board first, use debugger to inspect the peripheral registers (GPIO, RCC, SPI) and then compare with your direct coding.
2019-12-28 11:41 PM
I tried it. Registers seems same, only difference is that my code just feeds FIFO and there is nothing on the lines :\
2019-12-29 12:08 AM
As not experienced in F7/H7 I would just try to write DR byte by byte, waiting for the RXNE flag set before sending next byte,
With some timing vision, remember that a SPI master transaction completion is monitored by RNXE not TXE. Make sure your main() ends up into a while(1) loop to let the code not stop while SPI is sending. Check also the SPI clock source is present
2019-12-29 12:15 AM
Tath's what i've tried and did not work, but anyway thanks!
2019-12-29 04:28 AM
I'm not sure about it, but it looks like there is something wrong with the CS configuration. Maybe you could use some other GPIO for CS, handle that with SW and leave the HW NSS-pin not connected. At least the HW NSS didn't work too well in older chips. The problem was that if the SPI somehow "saw" that the NSS was in different state than what it expected, it gave mode error and switched to slave. And remember, even if the GPIO is programmed as output, the input is still attached.
You can use the HW NSS pin for SW CS, but you need to be careful with the configuration.
2019-12-29 08:45 AM
This NSS pin is not so big problem. Main issue is data transfer.
2019-12-29 01:50 PM
It is, if chip select causes the SPI to switch into slave mode and stop clocking.
BTW, what was the solution?
2019-12-29 01:59 PM
I don't know for sure but i rewrote CFG1 and 2 and changed TXD register access to 32-bit (before i was casting it to 8bit ptr)
2020-09-10 01:46 AM
Hey,
there were 2 places with mistakes
You get MODE FAULT because you first set SPI as master, but SSI is not SET.
I do not understand why ST made MASTER set outside CR1.
and second mistake was this:
// *(uint8_t *)SPI1->TXDR = a[i++];
you cast TXDR value to pointer and then write to its place ;)
it should have been:
*(uint8_t *)&SPI1->TXDR = a[i++];