STM32103 (BluePill) + SPI + PEtitFS = problem :(

Zestawy developrskie z mikrokontrolerami STM32 innych firm i nie tylko
ODPOWIEDZ
amilo
Nowy
Posty: 1
Rejestracja: 18 kwie 2018, 21:17

STM32103 (BluePill) + SPI + PEtitFS = problem :(

Post autor: amilo »

Witam,
Od kilku dni walczę z obsługą karty SD za pomocą SPI w STM32103 i nie mogę sobie poradzić.


Iniscjalizacja SPI:
  1. extern void SPI_init()
  2. {
  3.  
  4.     RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; //podłaczenie zegara SPI1
  5.     RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //podłaczenie zegara do portu A
  6.  
  7.  
  8.     gpio_pin_cfg(GPIOA, PA0, gpio_mode_output_PP_2MHz);     // konfiguracja pinu PA0 jako wyjścia pływającego
  9.     gpio_pin_cfg(GPIOA, PA5, gpio_mode_alternate_PP_10MHz); // konfiguracja pinu PA5 jako alternatywnego        /* SCK */
  10.     gpio_pin_cfg(GPIOA, PA6, gpio_mode_input_pull);         // konfiguracja pinu PA6 jako wejścia              /* MISO */
  11.     gpio_pin_cfg(GPIOA, PA7, gpio_mode_alternate_PP_10MHz); // konfiguracja pinu PA7 jako alternatywnego        /* MOSI */
  12.  
  13.  
  14.     SPI1->CR1 |= SPI_CR1_SSM;   //Linia NSS jest sterowana programowo
  15.     SPI1->CR1 |= SPI_CR1_SSI;   //Stan lini NSS jest wystawiany na nóżke
  16.     SPI1->CR1 |= SPI_CR1_MSTR;  //wybranie trybu typu master
  17.     SPI1->CR1 |= SPI_CR1_BR_0;
  18.     SPI1->CR1 |= SPI_CR1_SPE;   //włączenie SPI
  19.  
  20. }
Wybieranie slave'a
  1. void slaveSelect_ctrl (uint8_t state)
  2. {
  3.     if (state)
  4.     {
  5.         BB(GPIOA->ODR, PA0) = 0;        // activate slave
  6.     }
  7.     else
  8.     {
  9.         while(SPI1->SR & SPI_SR_BSY);
  10.         BB(GPIOA->ODR, PA0) = 1;        // deactivate slave
  11.     }
  12. }
Funkcie do wysyałania i odbierania danych po SPI
  1. void spi_write (uint8_t data)
  2. {
  3.     while(!(SPI1->SR & SPI_SR_TXE));    // sprawdzenie czy rejestr DR jest pusty
  4.     SPI1->DR = data;                    // wysłanie danych
  5.  
  6. }
  7.  
  8.  
  9. uint8_t spi_read (void)
  10. {
  11.     uint8_t data;
  12.  
  13.     while(!(SPI1->SR & SPI_SR_TXE));    // sprawdzenie czy rejestr DR jest pusty
  14.     SPI1->DR = 0xFF;                    // wysłanie danych
  15.     while(!(SPI1->SR & SPI_SR_RXNE));   // oczekiwanie na flagę inforującą, że odebraliśmy dane
  16.     data = SPI1->DR;                    // przepisanie odebranych danych
  17.     return data;
  18. }
Do obsługi karty kozystam z biblioteki PetitFS.
Jedyne zmiany jakie poczyniłem w tej biblitece to: zmiana wfunkcjach xmit_spi, rcv_spi (włożyłem tam moje funkcje do wysyłania i odbierania danych po SPI) oraz pozmieniałem definicje makr: SELECT(), DESELECT() oraz MMC_SEL
  1. /* USI control functions (Defined in usi.S, Platform dependent) */
  2. void xmit_spi (BYTE data)   /* Send a byte */
  3. {
  4.     spi_write(data);
  5. }
  6. BYTE rcv_spi (void) /* Send 0xFF and receive a byte */
  7. {
  8.     return spi_read();
  9. }
  10.  
  11.  
  12. /* Port Controls (Platform dependent) */
  13. #define SELECT()    slaveSelect_ctrl(0);        /* MMC CS = L */
  14. #define DESELECT()  slaveSelect_ctrl(1);        /* MMC CS = H */
  15. #define MMC_SEL     !(GPIOA->IDR & GPIO_IDR_IDR0)   /* MMC CS status (true:selected) */
  16. //#define   INIT_SPI()  { USICR = 0b00011000; }     /* Initialize SPI port */
Dla czytelności wklejam cały plik mmc.c
  1. /*-----------------------------------------------------------------------*/
  2. /* PFF - Low level disk control module for ATtiny85     (C)ChaN, 2009    */
  3. /*-----------------------------------------------------------------------*/
  4.  
  5. #define _WRITE_FUNC 1
  6.  
  7. //#include <avr/io.h>
  8. #include "diskio.h"
  9. #include "../UART/UART.h"
  10. #include "../SPI/spi.h"
  11. //#include "suart.h"
  12.  
  13.  
  14. /* Definitions for MMC/SDC command */
  15. #define CMD0    (0x40+0)    /* GO_IDLE_STATE */
  16. #define CMD1    (0x40+1)    /* SEND_OP_COND (MMC) */
  17. #define ACMD41  (0xC0+41)   /* SEND_OP_COND (SDC) */
  18. #define CMD8    (0x40+8)    /* SEND_IF_COND */
  19. #define CMD16   (0x40+16)   /* SET_BLOCKLEN */
  20. #define CMD17   (0x40+17)   /* READ_SINGLE_BLOCK */
  21. #define CMD24   (0x40+24)   /* WRITE_BLOCK */
  22. #define CMD55   (0x40+55)   /* APP_CMD */
  23. #define CMD58   (0x40+58)   /* READ_OCR */
  24.  
  25.  
  26. /* USI control functions (Defined in usi.S, Platform dependent) */
  27. void xmit_spi (BYTE data)   /* Send a byte */
  28. {
  29.     spi_write(data);
  30. }
  31. BYTE rcv_spi (void) /* Send 0xFF and receive a byte */
  32. {
  33.     return spi_read();
  34. }
  35.  
  36.  
  37. /* Port Controls (Platform dependent) */
  38. #define SELECT()    slaveSelect_ctrl(0);        /* MMC CS = L */
  39. #define DESELECT()  slaveSelect_ctrl(1);        /* MMC CS = H */
  40. #define MMC_SEL     !(GPIOA->IDR & GPIO_IDR_IDR0)   /* MMC CS status (true:selected) */
  41. //#define   INIT_SPI()  { USICR = 0b00011000; }     /* Initialize SPI port */
  42.  
  43. /*--------------------------------------------------------------------------
  44.  
  45.    Module Private Functions
  46.  
  47. ---------------------------------------------------------------------------*/
  48.  
  49. static
  50. BYTE CardType;
  51.  
  52.  
  53. /*-----------------------------------------------------------------------*/
  54. /* Deselect the card and release SPI bus                                 */
  55. /*-----------------------------------------------------------------------*/
  56.  
  57. static
  58. void release_spi (void)
  59. {
  60.     DESELECT();
  61.     rcv_spi();
  62. }
  63.  
  64.  
  65. /*-----------------------------------------------------------------------*/
  66. /* Send a command packet to MMC                                          */
  67. /*-----------------------------------------------------------------------*/
  68.  
  69. static
  70. BYTE send_cmd (
  71.     BYTE cmd,       /* Command byte */
  72.     DWORD arg       /* Argument */
  73. )
  74. {
  75.     BYTE n, res;
  76.  
  77.  
  78.     if (cmd & 0x80) {   /* ACMD<n> is the command sequense of CMD55-CMD<n> */
  79.         cmd &= 0x7F;
  80.         res = send_cmd(CMD55, 0);
  81.         if (res > 1) return res;
  82.     }
  83.  
  84.     /* Select the card */
  85.     DESELECT();
  86.     rcv_spi();
  87.     SELECT();
  88.     rcv_spi();
  89.  
  90.     /* Send a command packet */
  91.     xmit_spi(cmd);                      /* Start + Command index */
  92.     xmit_spi((BYTE)(arg >> 24));        /* Argument[31..24] */
  93.     xmit_spi((BYTE)(arg >> 16));        /* Argument[23..16] */
  94.     xmit_spi((BYTE)(arg >> 8));         /* Argument[15..8] */
  95.     xmit_spi((BYTE)arg);                /* Argument[7..0] */
  96.     n = 0x01;                           /* Dummy CRC + Stop */
  97.     if (cmd == CMD0) n = 0x95;          /* Valid CRC for CMD0(0) */
  98.     if (cmd == CMD8) n = 0x87;          /* Valid CRC for CMD8(0x1AA) */
  99.     xmit_spi(n);
  100.  
  101.     /* Receive a command response */
  102.     n = 10;                             /* Wait for a valid response in timeout of 10 attempts */
  103.     do {
  104.         res = rcv_spi();
  105.     } while ((res & 0x80) && --n);
  106.  
  107.     return res;         /* Return with the response value */
  108. }
  109.  
  110.  
  111.  
  112. /*--------------------------------------------------------------------------
  113.  
  114.    Public Functions
  115.  
  116. ---------------------------------------------------------------------------*/
  117. #if _WRITE_FUNC
  118.  
  119.     void write_close(void)
  120.     {
  121.         BYTE res = disk_writep(0,0);
  122.         uint8_t i;
  123.         for (i=0; i<100 && res; i++) res = disk_writep(0,0);
  124.     }
  125. #endif
  126.  
  127. /*-----------------------------------------------------------------------*/
  128. /* Initialize Disk Drive                                                 */
  129. /*-----------------------------------------------------------------------*/
  130.  
  131. DSTATUS disk_initialize (void)
  132. {
  133.     BYTE n, cmd, ty, ocr[4];
  134.     WORD tmr;
  135.  
  136.  
  137. //  INIT_SPI();
  138.  
  139.  
  140. #if _WRITE_FUNC
  141.     if (MMC_SEL) disk_writep(0, 0);     /* Finalize write process if it is in progress */
  142.  
  143.  
  144. #endif
  145.     for (n = 100; n; n--) rcv_spi();    /* Dummy clocks */
  146.  
  147.     ty = 0;
  148.     if (send_cmd(CMD0, 0) == 1) {           /* Enter Idle state */
  149.         if (send_cmd(CMD8, 0x1AA) == 1) {   /* SDv2 */
  150.             for (n = 0; n < 4; n++) ocr[n] = rcv_spi();     /* Get trailing return value of R7 resp */
  151.             if (ocr[2] == 0x01 && ocr[3] == 0xAA) {             /* The card can work at vdd range of 2.7-3.6V */
  152.                 for (tmr = 12000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) ;  /* Wait for leaving idle state (ACMD41 with HCS bit) */
  153.                 if (tmr && send_cmd(CMD58, 0) == 0) {       /* Check CCS bit in the OCR */
  154.                     for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
  155.                     ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;  /* SDv2 (HC or SC) */
  156.                 }
  157.             }
  158.         } else {                            /* SDv1 or MMCv3 */
  159.             if (send_cmd(ACMD41, 0) <= 1)   {
  160.                 ty = CT_SD1; cmd = ACMD41;  /* SDv1 */
  161.             } else {
  162.                 ty = CT_MMC; cmd = CMD1;    /* MMCv3 */
  163.             }
  164.             for (tmr = 25000; tmr && send_cmd(cmd, 0); tmr--) ; /* Wait for leaving idle state */
  165.             if (!tmr || send_cmd(CMD16, 512) != 0)          /* Set R/W block length to 512 */
  166.                 ty = 0;
  167.         }
  168.     }
  169.     CardType = ty;
  170.     release_spi();
  171.  
  172.     return ty ? 0 : STA_NOINIT;
  173. }
  174.  
  175.  
  176.  
  177. /*-----------------------------------------------------------------------*/
  178. /* Read partial sector                                                   */
  179. /*-----------------------------------------------------------------------*/
  180.  
  181. DRESULT disk_readp (
  182.     BYTE *buff,     /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
  183.     DWORD lba,      /* Sector number (LBA) */
  184.     WORD ofs,       /* Byte offset to read from (0..511) */
  185.     WORD cnt        /* Number of bytes to read (ofs + cnt mus be <= 512) */
  186. )
  187. {
  188.     DRESULT res;
  189.     BYTE rc;
  190.     WORD bc;
  191.  
  192.  
  193.     if (!(CardType & CT_BLOCK)) lba *= 512;     /* Convert to byte address if needed */
  194.  
  195.     res = RES_ERROR;
  196.     if (send_cmd(CMD17, lba) == 0) {        /* READ_SINGLE_BLOCK */
  197.  
  198.         bc = 30000;
  199.         do {                            /* Wait for data packet in timeout of 100ms */
  200.             rc = rcv_spi();
  201.         } while (rc == 0xFF && --bc);
  202.  
  203.         if (rc == 0xFE) {               /* A data packet arrived */
  204.             bc = 514 - ofs - cnt;
  205.  
  206.             /* Skip leading bytes */
  207.             if (ofs) {
  208.                 do rcv_spi(); while (--ofs);
  209.             }
  210.  
  211.             /* Receive a part of the sector */
  212.             if (buff) { /* Store data to the memory */
  213.                 do
  214.                     *buff++ = rcv_spi();
  215.                 while (--cnt);
  216.             } else {    /* Forward data to the outgoing stream (depends on the project) */
  217.                 do
  218.                     uart_putc(rcv_spi());/* (Console output) */
  219. //                  xmit(rcv_spi());    /* (Console output) */
  220.                 while (--cnt);
  221.             }
  222.  
  223.             /* Skip trailing bytes and CRC */
  224.             do rcv_spi(); while (--bc);
  225.  
  226.             res = RES_OK;
  227.         }
  228.     }
  229.  
  230.     release_spi();
  231.  
  232.     return res;
  233. }
  234.  
  235.  
  236.  
  237. /*-----------------------------------------------------------------------*/
  238. /* Write partial sector                                                  */
  239. /*-----------------------------------------------------------------------*/
  240. #if _WRITE_FUNC
  241.  
  242. DRESULT disk_writep (
  243.     const BYTE *buff,   /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
  244.     DWORD sa            /* Number of bytes to send, Sector number (LBA) or zero */
  245. )
  246. {
  247.     DRESULT res;
  248.     WORD bc;
  249.     static WORD wc;
  250.  
  251.  
  252.     res = RES_ERROR;
  253.  
  254.     if (buff) {     /* Send data bytes */
  255.         bc = (WORD)sa;
  256.         while (bc && wc) {      /* Send data bytes to the card */
  257.             xmit_spi(*buff++);
  258.             wc--; bc--;
  259.         }
  260.         res = RES_OK;
  261.     } else {
  262.         if (sa) {   /* Initiate sector write process */
  263.             if (!(CardType & CT_BLOCK)) sa *= 512;  /* Convert to byte address if needed */
  264.             if (send_cmd(CMD24, sa) == 0) {         /* WRITE_SINGLE_BLOCK */
  265.                 xmit_spi(0xFF); xmit_spi(0xFE);     /* Data block header */
  266.                 wc = 512;                           /* Set byte counter */
  267.                 res = RES_OK;
  268.             }
  269.         } else {    /* Finalize sector write process */
  270.             bc = wc + 2;
  271.             while (bc--) xmit_spi(0);   /* Fill left bytes and CRC with zeros */
  272.             if ((rcv_spi() & 0x1F) == 0x05) {   /* Receive data resp and wait for end of write process in timeout of 300ms */
  273.                 for (bc = 65000; rcv_spi() != 0xFF && bc; bc--) ;   /* Wait ready */
  274.                 if (bc) res = RES_OK;
  275.             }
  276.             release_spi();
  277.         }
  278.     }
  279.  
  280.     return res;
  281. }
  282. #endif
I teraz w pętli głównej chcę zrobić inicjalizację karty, odczyt zawartości, modyfikacja i zapis zmienionych danych:
  1. while ( i-- && (res = disk_initialize()));  /*inicjalizacja karty SD*/
  2.     if(res == FR_OK)                            /*sprawdzenie czy powiodła się inicjalizacja*/
  3.     {
  4.         res = pf_mount(&fs);                    /*inicjalizacja napędu logicznego w strukturze fs*/
  5.         if (res == FR_OK)
  6.         {
  7.             res =  pf_open(file_name);          /*otwarcie naszego pliku*/
  8.             if (res ==  FR_OK)
  9.             {
  10.                 res = pf_read(bufor, sizeof(bufor), &s1);   /*odczyt danych z pliku do bufora*/
  11.                 if(res == FR_OK)
  12.                 {
  13.                     bufor[s1 + 1] = 0;
  14.                     uart_puts(bufor);           /*wyświetlenie zawartosci bufora*/
  15. //                  _delay_ms(3000);
  16.                     uart_puts("\n\r");
  17.                     uart_puts("zapis -> test.txt");
  18.                     uart_puts("\n\r");
  19.                     if(bufor[0] == 't') sprintf(bufor, "TEST ****");
  20.                     else                sprintf(bufor, "test ----");
  21.  
  22.                     s1=4;
  23.                     res = pf_write(bufor, sizeof(bufor), &s1);
  24. //                  pf_write(0, 0, &w);
  25.  
  26.                     if(res != FR_OK)    uart_puts("write file error");
  27.                     else                uart_puts("OK, zresetuj");
  28.                     uart_puts("\n\r");
  29.  
  30.                     pf_mount(NULL);
  31.                     write_close();
  32.                 }
  33.                 else
  34.                     {
  35.                         uart_puts("read error");
  36.                         uart_puts("\n\r");
  37.                     }
  38.  
  39.             }
  40.             else
  41.             {
  42.                 uart_puts("open file error");
  43.                 uart_puts("\n\r");
  44.             }
  45.         }
  46.         else
  47.         {
  48.             uart_puts("mount error");
  49.             uart_puts("\n\r");
  50.         }
  51.     }
  52.     else
  53.     {
  54.         uart_puts("disk init error");
  55.         uart_puts("\n\r");
  56.     }
Po tych operacjach otrzymuję informacje "disk init error"
Obraz wysłany z ..:: Forum amatorów i pasjonatów elektroniki oraz programowania
Na podglądzie magistrali, na linii MOSI procek cały czas wysyła 0x00

A tak wygląda cały przebieg:
Obraz wysłany z ..:: Forum amatorów i pasjonatów elektroniki oraz programowania

Wnioskuję, że mam źle napisane funkcje do wysyłania i odbierania danych po SPI i/lub źle skonfugurowany port SPI.
Proszę o pomoc i o sprawdzenie moich wypocin :)

ODPOWIEDZ

Wróć do „STM32 Development BOARD”