Jobber med et SD-kort. Tilkobling til mikrokontroller. Del 1. Koble et SD-kort til en mikrokontroller Koble SD-mmc-kort til en mikrokontroller

God dag alle sammen! I dag skal vi snakke om koble til et SD-minnekort til STM32-mikrokontrolleren.

Det ser ut til at STM32F10x-kontrollerne har rikelig med minne, hvorfor skulle det være mer, men dette inntrykket er villedende) For eksempel må vi vise et par forskjellige bilder– format 320*240 – det vil si 76800 piksler, som hver tilsvarer så mange som 2 byte. Så vi får omtrent 150 kB per bilde. Og dette er mye etter standarden til en mikrokontroller, og det er ikke et faktum at to forskjellige bilder kan stappes inn i Flash-minnet. Eller trenger vi å lagre store mengder informasjon, for eksempel data fra en eller annen sensor. Dessuten, slik at disse dataene er tilgjengelige selv etter at strømmen er slått av. Det er her det kommer godt med for oss eksternt minne. Og en flott løsning ville være SD-minnekort eller MMC. Forresten, i denne artikkelen vil vi gjennomføre eksperimenter på micro SD-kort.

Først noen få ord om selve minnekortet, eller mer presist om pinout. Det hele ser slik ut:

Så hva har vi her? Vel, det er umiddelbart klart at den har åtte pinner. Pin-tilordningene er som følger (fra venstre til høyre):


SPI-moduskolonnen antyder at den samhandler med mikrokontrolleren ved hjelp av SPI-grensesnittet. MEN! Vi tar en annen vei 😉 Saken er at STM32 har ombord en ferdig perifermodul for arbeid med minnekort, og den heter SDIO.

Generelt innebærer interaksjon med minnekort å sende dem visse kommandoer. Noen kommandoer krever et argument, noen ikke. Kommandoer finnes i den offisielle dokumentasjonen for et bestemt kort. Så den innebygde SDIO-modulen gjør det mulig å betydelig forenkle prosessen med å overføre kommandoer, og faktisk prosessen med å jobbe med eksterne kort hukommelse. For eksempel, her er registeret SDIO_CMD– der skriver vi bare ned koden til kommandoen som vi ønsker å overføre til kortet. Eller her er statusregisteret SDIO_STA– det er så mange som 24 flagg for hvert nys, det vil si for et stort antall arrangementer.

STM gleder seg forresten også med god dokumentasjon på hele denne saken. Her er det f.eks. Detaljert beskrivelse initialisering for et SD-minnekort (alt beskrives på samme måte for andre typer kort):

Vel, faktisk er det på tide å gå videre til et praktisk eksempel. La oss grave inn i Standard Peripheral Library.

I fil stm32f10x_sdio.h Tradisjonelt finner vi strukturer for alle slags innstillinger - det vil si for å velge kilden til klokkesignalet, frekvensen til SDIO-kontrolleren og stille inn antall byte som overføres. Alt der er så sjenerøst kommentert at jeg ikke engang vil gjenta det separat)) Bare se:

typedef struct (uint32_t SDIO_ClockEdge; /* Spesifiserer klokkeovergangen som bitfangsten gjøres på. Denne parameteren kan være verdien @ref SDIO_Clock_Edge */ uint32_t SDIO_ClockBypass; /* Angir om SDIO Clock divider-bypass er aktivert eller deaktivert. Denne parameteren kan være verdien @ref SDIO_Clock_Bypass */ uint32_t SDIO_ClockPowerSave; /* Angir om SDIO-klokkeutgang er aktivert eller deaktivert når bussen er inaktiv. Denne parameteren kan være verdien @ref SDIO_Clock_Power_Save */ uint32_t SDIO_BusWide; /* Spesifiserer SDIO-bussbredden. Denne parameteren kan være verdien @ref SDIO_Bus_Wide */ uint32_t SDIO_HardwareFlowControl; /* Angir om SDIO-maskinvareflytkontrollen er aktivert eller deaktivert. Denne parameteren kan være verdien @ref SDIO_Hardware_Flow_Control */ uint8_t SDIO_ClockDiv; /* Spesifiserer klokkefrekvensen til SDIO-kontrolleren. Denne parameteren kan være en verdi mellom 0x00 og 0xFF. */) SDIO_InitTypeDef; typedef struct (uint32_t SDIO_Argument; /* Spesifiserer SDIO-kommandoargumentet som sendes til et kort som en del av en kommandomelding. Hvis en kommando inneholder et argument, må den lastes inn i dette registeret før du skriver kommandoen til kommandoregisteret */ uint32_t SDIO_CmdIndex; /* Spesifiserer SDIO-kommandoindeksen. Den må være lavere enn 0x40. */ uint32_t SDIO_Response; /* Spesifiserer SDIO-responstypen. Denne parameteren kan være verdien @ref SDIO_Response_Type */ uint32_t SDIO_Wait; /* Angir om SDIO vente-på-avbrudd-forespørsel er aktivert eller deaktivert. Denne parameteren kan være verdien @ref SDIO_Wait_Interrupt_State */ uint32_t SDIO_CPSM; /* Angir om SDIO Command path state machine (CPSM) er aktivert eller deaktivert. Denne parameteren kan være verdien @ref SDIO_CPSM_State */) SDIO_CmdInitTypeDef; typedef struct (uint32_t SDIO_DataTimeOut; /* Spesifiserer tidsavbruddsperioden for data i kortbuss-klokkeperioder. */ uint32_t SDIO_DataLength; /* Angir antall databyte som skal overføres. */ uint32_t SDIO_DataBlockSize; /* Spesifiserer datablokkstørrelsen for blokkoverføring. Denne parameteren kan være verdien @ref SDIO_Data_Block_Size */ uint32_t SDIO_TransferDir; /* Spesifiserer dataoverføringsretningen, om overføringen er lesing eller skriving. Denne parameteren kan være verdien @ref SDIO_Transfer_Direction */ uint32_t SDIO_TransferMode; /* Angir om dataoverføring er i strøm- eller blokkmodus. Denne parameteren kan være verdien @ref SDIO_Transfer_Type */ uint32_t SDIO_DPSM; /* Angir om SDIO Datapath State Machine (DPSM) er aktivert eller deaktivert. Denne parameteren kan være verdien @ref SDIO_DPSM_State */) SDIO_DataInitTypeDef;

La oss legge merke til hvordan SPL implementerer overføring av kommandoer til et minnekort. Det er avsatt en egen struktur for disse formålene. SDIO_CmdInitTypeDef. I felt SDIO_CmdIndex skriv inn kommandokoden i feltet SDIO_Argument– kommandoargument, fyll også ut de resterende feltene. Alt som gjenstår er å på en eller annen måte stappe disse dataene inn mikrokort SD 😉 Og for dette utarbeidet de en funksjon for oss:

SDIO_SendCommand (SDIO_CmdInitTypeDef *SDIO_CmdInitStruct)

Som et argument gir vi det strukturen vi skapte. For å registrere data er det en funksjon - SDIO_WriteData(uint32_t Data). Etter å ha kalt denne funksjonen, vil dataene være i et register spesialdesignet for dette formålet - SDIO_FIFO.

Slik jobber du med SDIO-modulen i STM32F10x)

La oss nå endelig gå videre til praksis. Jeg skal jobbe med igjen Minibrett STM32, fordi de gode kineserne ble forvirret ved å installere et spor for et micro SD-minnekort på den. Her er et diagram over tilkobling av kortkontakten til mikrokontrolleren:

For å skrive programmet vi skal bruke ferdige eksempel for Keil - la oss ta to filer derfra, der noe som en driver for arbeid med kort er implementert - dette er filene sdcard.c Og sdcard.h. Vi skaper nytt prosjekt, legger vi ved disse filene der, og i tillegg, selvfølgelig, CMSIS- og SPL-filene. Her er det ferdige prosjektet, der alt allerede er lagt til - alt som gjenstår er å skrive koden for hoved()-funksjonen)

Filen sdcard.c implementerer alle slags funksjoner for å jobbe med et minnekort, nå er det bare å bruke dem 😉 La oss skrive koden! La oss for eksempel skrive 512 byte med testdata til micro SD, og ​​deretter prøve å lese dem:

// Koble til de nødvendige filene#inkluder "stm32f10x.h" #inkluder "sdcard.h" /*******************************************************************/ // Matriser med inn- og utdata og en variabel for lagring av data// om kortet vårt uint8_t writeBuffer[ 512 ] ; uint8_t readBuffer[ 512 ] ; SD_CardInfo SDCardInfo; /*******************************************************************/ int main() ( // Test data for å skrive for (uint16_t i = 0 ; i< 512 ; i++ ) { writeBuffer[ i] = i % 256 ; readBuffer[ i] = 0 ; } // Initialiser kartet SD_Init() ; // Få informasjon om kortet SD_GetCardInfo(& SDCardInfo) ; // Velge et kort og stille inn driftsmodus SD_SelectDeselect((uint32_t) (SDCardInfo.RCA<< 16 ) ) ; SD_SetDeviceMode(SD_POLLING_MODE) ; // Og til slutt, skriving og lesing SD_WriteBlock(0x00, skrivebuffer, 512) ; SD_ReadBlock(0x00, readBuffer, 512) ; mens (1) ( )) /*******************************************************************/

Vær oppmerksom på at SD-kortet støtter opptak i blokker på 512 byte.

Hvis vi kjører programmet under feilsøkeren, vil vi se at de leste dataene samsvarer med de skrevne data =) Så vi kan vurdere eksperimentet som en suksess. Det var alt for i dag, vi sees snart!

  • Andreas sier:

    Å montere en Memory Stick-adapter med egne hender er ikke vanskelig hvis du vet formålet med de funksjonelle pinnene til et bestemt minnekort. Vanligvis kalt pinouten til et minnekort eller for eksempel en mikrokrets, brikke osv. Generelt er teknologien enkel. Oppsettet til MMC-minnekortet (MultiMedia Card) er kuttet ut fra PCB. 7 spor kuttes ut på brødbrettet (MMC har 7 pinner). Deretter, i samsvar med pinouten vist i figuren nedenfor, loddes sporene til pinnene på SD-minnekortet (har 9 pinner, hvorav 2 ikke brukes), microSD (har 8 pinner, hvorav 2 heller ikke brukt, men merk at kortets microSD-minne ikke har noen Vcc-utgang) eller microM2 (microM2 pinout i det relaterte emnet Memory Stick Micro M2 Adapter). Det er alt. Memory Stick-adapteren er klar.

    P.S. Vi har 1 og 2 GB MMC minnekort på lager. Kostnaden er henholdsvis 285 og 360 rubler. Levering er inkludert i oppgitt pris.

    Du kan også kjøpe følgende størrelser av minnekort billig:
    - Memory Stick og Memory Stick M2;
    - Secure Digital (SD);
    - Mini SD;
    - Micro SD (TF);
    - Compact Flash;
    -XD;
    - USB-minnepinner med ulike design og kapasiteter.
    For eksempel disse:

  • slava sier:

    Forresten, jeg er ikke veldig tydelig i disse skriftene. Du kan ikke få sporene fra MicroCD til MMC på den siden, jeg vil være veldig takknemlig.

  • Andreas sier:

    Slik vil microSD til MMC-adapteren se ut:

  • slava sier:
  • Som det fremgår av figuren, etter overføring av kommandorammen, er det nødvendig å fortsette å lese byte (Ncr) fra microSD til du mottar et svar (R1), mens CS-nivået må være aktivt "0".

    Avhengig av kommandoindeksen er svaret kanskje ikke bare R1(se sett med grunnleggende kommandoer) på CMD58-svar R3(R1 og den avsluttende 32-biters OCR-verdien), og noen kommandoer krever mer NCR-tid og vil svare R1b. Dette er R1-svaret, etterfulgt av et opptatt flagg (signalet på "DO"-linjen holdes lavt av kortet mens den interne prosessen fortsetter). Vertskontrolleren må vente på at prosessen skal fullføres til "DO" blir høy (dvs. vente på 0xFF). Og også R2 når du ber om status for STATUS-registeret.

    Responsen R1 inneholder 1 byte, strukturen kan sees i tabellen nedenfor. Responsen R2 består av to byte, den første byte er R1 og den andre er R2 (se R2 strukturtabell). Og svaret R3 er henholdsvis 5 byte.


    Respons R1 med verdi 0x00 betyr at kommandoen ble fullført, ellers vil det tilsvarende flagget bli satt.

    Struktur av svar R1.


    R2 responsstruktur.


    Initialisering i SPI-modus.

    Etter en tilbakestilling og strømforsyning er kortet som standard satt til driftsmodus ved hjelp av MMC (Serial Peripheral Interface)-protokollen; for å bytte til SPI-modus må du gjøre følgende:

    1. Etter å ha nådd 2,2 V, vent minst et millisekund, sett DI- og CS-linjene høyt og avgi omtrent 80 pulser til CLK-pinnen. Etter denne prosedyren vil kortet være klart til å akseptere hjemmelaget.
    2. Send kommando CMD0 (myk tilbakestilling). Kortet må svare (R1) med ventebiten satt (0x01).
    3. Send kommando CMD1 (for å begynne å initialisere kortet). Vent på svar 0x00 for å bekrefte at prosessen er fullført initialisering.

    La meg minne deg på at CMD0-kommandoen må inneholde riktig CRC-felt. Det er ingen vits i å beregne, siden det ikke er noen argumenter i denne kommandoen, så den er konstant og har verdien 0x95. Når kortet går inn i SPI-modus, vil CRC-funksjonen bli deaktivert og vil ikke bli sjekket. CRC-alternativet kan aktiveres på nytt med CMD59.

    Som et resultat vil CMD0-kommandoen se slik ut: 0x40.0x00.0x00.0x00.0x00.0x95.

    • lagindeks - 0x40.
    • argument – ​​0x00.0x00.0x00.0x00.
    • CRC-0x95.

    Når det gjelder 80 pulser, kan de genereres ved å overføre verdien 0xFF via SPI10 ganger på radpå høye nivåer satt på linjene DI og CS.

    Etter å ha vært inaktiv i mer enn 5 ms, går minnekortet over i strømsparingsmodus og kan kun akseptere CMD0, CMD1 og CMD58 kommandoer. Derfor må initialiseringsprosessen (CMD1) gjentas nesten hver gang når du leser/skriver en datablokk eller sjekker statusen til kortet.

    For SDC-kort hvis kommandoen avvisesCMD1 anbefales for å bruke ACMD41-kommandoen.

    Selve initialiseringsprosessen kan ta relativt lang tid (avhengig av størrelsen på kortet) og kan nå hundrevis av millisekunder.

    Lese og skrive en datablokk.

    Som standard, i SPI-modus, utføres utveksling mellom mikrokontrolleren og kortet i blokker på 512 byte, så for å skrive enda en byte må du først lese hele blokken og, ved å endre byte, skrive den tilbake. Blokkstørrelsen kan endres i CSD-registeret på minnekortet.

    For å unngå adresseringsfeil når du utfører lese-/skrivekommandoer, er det nødvendig at adressen er tydelig angitt i begynnelsen av sektoren. For å gjøre dette kan du tilbakestille bit "0" 3 byte av sektoradressen, dvs. gjør det jevnt, og den mindre bør alltid ha verdien 0x00.

    Leser en datablokk.

    Algoritmen for å lese en datablokk er som følger:

    • Etter å ha bekreftet initialisering, sender vi kommandoen CMD17 (svar R1), med adressen til den nødvendige sektoren.
    • Vi sender 0xFF før vi mottar startbyten 0xFE.
    • Vi godtar en datablokk (512 byte som standard) og 2 byte med CRC.

    CRC-verdien er ikke nødvendig, men akseptprosedyren (overføring av 0xFF fra MK) er nødvendig.

    Leseblokk.


    Skriv en datablokk.

    Algoritmen for å skrive en datablokk er som følger:

    • Hvis kortet var inaktivt i mer enn 5 ms, send CMD1-kommandoen (svar R1).
    • Etter å ha bekreftet initialisering, sender vi CMD24-kommandoen (svar R1), med adressen til den nødvendige sektoren.
    • Vi overfører startbyten 0xFE.
    • Vi overfører en datablokk (512 byte som standard) og 2 byte CRC.
    • Vi mottar skrivebekreftelsesbyten.
    • Vi venter på slutten av opptaket (endring av byte 0x00).

    Datablokken kan være mindre enn 512 byte når du endrer blokklengden med CMD16-kommandoen.

    CRC-verdien er ikke nødvendig, men prosedyren for å sende eventuelle verdier er nødvendig.

    Du kan ikke gjøre nedetidsvurderingen programmatisk, men umiddelbart gi en initialiseringskommando. Under programvareimplementeringen møtte jeg et feil opptak, av en eller annen grunn ble alle bytene skrevet til en venstreforskjøvet sektor. Problemet ble løst bare ved å sende startbiten (0xFE) to ganger.

    Blokker opptak.


    Bekreftelsesbyte når du skriver en datablokk.


    Skriv/les flere blokker på rad.

    Bruke kommandoer CMD18, CMD25 du kan lese/skrive flere blokker på rad eller den såkalte multiblokk lese/skrive. Hvis antall blokker ikke er spesifisert, kan lese-/skriveprosessen stoppes ved å bruke CMD12-kommandoer under lesing, samt ved å sende " Stopp Tran" når du tar opp tilsvarende.

    Praktisk bruk.

    Den praktiske bruken av minnekort er ganske bred. I sitt nyeste design brukte han microSD til å registrere avlesninger fra ulike sensorer (temperatur, alarm) gjennom dagen hver time. Data lagres som følger:

    • Året er hentet fra de to siste sifrene - dette tilsvarer den første (hoved)byten til minnekortets sektoradresse.
    • Måned, to sifre - dette tilsvarer den andre, mest betydningsfulle byten til minnekortets sektoradresse.
    • Dag, to siffer multipliseres med 2 (for å unngå å treffe utenfor sektorgrensen) - dette er den tredje, midterste byten til minnekortets sektoradresse.
    • Den lave orden, fjerde byte er alltid "0".

    Som et resultat er det forenklet å søke etter data etter dato; du trenger bare å oversette forespørselen til sektoradressen og lese fra kortet. Med denne metoden kan data lagres i flere år. Riktignok er det også ulemper; det er mye ubrukt plass igjen. Selv om du, om ønskelig, kan bruke den til andre oppgaver.

    Hvem trenger det, jeg sender deg et kodefragment i assembler for 18 topper.

    Spørsmål kan stilles på..

    Så lenge jeg kan huske har jeg alltid elsket å lese, men dette er det 21. århundre og noen ganger kan nødvendig litteratur bare finnes på Internett. Ja, og du kan lese e-bøker på en elektronisk enhet som nettbrett, datamaskin eller e-leser. Resultatet er en liten enhet som kan lese tekstfiler fra et SD- eller microSD-kort og vise innholdet på skjermen.

    Hjernen til enheten er Atmega32-mikrokontrolleren som opererer med en frekvens på 8 MHz. MK er klokket fra en ekstern kvarts på 8 MHz; Jeg brukte en liten WH1604A LCD-indikator på HD44780-kontrolleren med en oppløsning på 4 linjer med 16 tegn hver som enhetsskjerm. Jeg brukte vanlige klokkeknapper; når det gjelder SD-kortet, for å koble det til mikrokontrolleren, brukte jeg motstandsdelere for å matche de logiske nivåene.

    Skjematisk diagram av enheten:

    Pinouten i diagrammet er kun riktig for et SD-kort eller SD-adapter; for å koble til andre kort, bruk deres pinout!

    Enheten støtter SD-, miniSD- og microSD-minnekort på opptil 4 GB formatert i filsystemet FAT, FAT16. Det bør huskes at enheten ikke støtter kataloger, så alle filer må bare skrives til roten av flash-stasjonen. Tekstfiler må være i vanlig txt-format og uten formatering, filnavn må ikke være lengre enn 8 tegn (ikke medregnet filtypen).

    Når du slår på enheten, vil en splash-skjerm vises på skjermen:

    Hvis SD-kortet ikke er installert i enheten, er feil tilkoblet eller noe annet, vises følgende melding:

    Hvis alt er i orden, vises hovedmenyen:

    Ved å bruke knappene kan du gå inn i «Bla gjennom filer»-elementet der du kan velge filen du trenger å lese.

    I "Innstillinger"-elementet kan du velge hvilken filtype du vil vise filer i "Filleseren".

    Og i det siste avsnittet "Om systemet ..." kan du lese informasjon om enheten, dens forfatter, etc.

    Jeg skrev fastvaren for enheten i BASCOM-AVR-miljøet ved hjelp av AVRDOS-biblioteket, fastvaren tar kun opp 30% av mikrokontrollerens programminne, så det er rom for kreativitet. Innvendig er enheten satt sammen på to trykte kretskort: på den ene er det en MK med et kroppssett, på den andre er det en kontakt for et SD-kort og matchende kjeder med logiske nivåer.

    Her er et bilde av enheten inne:

    For strømforsyning brukte jeg et 4,8V, 600mAh Ni-Cd-batteri. Etter å ha blinket mikrokontrolleren, må du stille inn følgende sikringsbiter:

    Liste over radioelementer

    Betegnelse Type Valør Mengde MerkButikkNotisblokken min
    U1 MK AVR 8-bit

    ATmega32

    1 Til notisblokk
    D1, D2 Likeretterdiode

    1N4001

    2 Til notisblokk
    C1, C2 Kondensator22 pF2 Til notisblokk
    C3 Elektrolytisk kondensator100 µF1 Til notisblokk
    C4 Kondensator100 nF1 Til notisblokk
    R1 Motstand

    10 kOhm

    1 Til notisblokk
    R2-R4 Motstand

    4,7 kOhm

    3 Til notisblokk
    R5-R7 Motstand

    1 kOhm

    3 Til notisblokk
    LCD1 LCD-skjermLM014L1 Til notisblokk
    X1 Kvarts8 MHz1 Til notisblokk
    Knapp 4 Til notisblokk
    Bytte om 1

    Oppdatert 18.12.15. Hei alle sammen. I dag vil vi fortsette utviklingen av datainnsamlingsansvarlig, nemlig lagring av informasjon direkte på SD kort . I den siste artikkelen ble driften av termometeret etablert. Nå denne informasjonen på tid når du kobler til V ytterligere sanntidsklokke(artikkel nr. 29), legger vi det på minnekortet og får en slags database. Og også i fremtiden vil vi overføre denne informasjonen til en PC (artikkel nr. 42), til en database som kjører MySQL (artikkel nr. 48), gjennom en liten applikasjon i Java (artikkel nr. 44). Men først, la oss finne ut hva et SD-kort er og hvordan du arbeider med det.La oss starte med en kort historie. Forgjengeren til Flash-minne er en av de ikke-flyktige minnetypene, type, som har bevist seg og brukes i mikrokontrollere. Flash-minne oppsto fra behovet for økt kapasitet og endringer i sletteteknologi (når det gjelder EPROM-minne). Derfor endret Toshiba-ingeniøren Fujio Masuokoi i 1984 sletteteknologien, som igjen løste manglene til forgjengerne til Flash-minne. Jeg vil gjerne legge til at ytterligere dette minnet begynte å bli delt i henhold til den interne enheten for å koble celler til en matrise og lese-skrive-algoritmer - dette er NOR- og NAND-teknologi. Og også forskjellen i antall lagrede biter i en elementær celle. Dette er SLC-enheter (single-levelcell), dvs. enkeltbitsceller skiller bare to ladningsnivåer på den flytende porten. Og MLC-enheter (multi-levelcell) - multi-bit celler skiller flere ladenivåer. Den andre typen enhet er billigere og mer romslig enn SLC-enheter, men med lengre tilgangstider og et mindre maksimalt antall overskrivinger (omtrent 10 tusen og 100 tusen for SLC).

    Generelt er NOR-teknologienheter en todimensjonal matrise av ledere, som gir raskere tilgang til hver minnecelle, men cellearealet anses som stort, så denne teknologien brukes til mikroprosessorprogramminne og for lagring av små hjelpedata, og spesialisert de kan også inkluderes her. datamaskin boot-brikker
    (POST og BIOS), DSP-prosessorer og programmerbar logikk Typiske volumer - fra 1 KB til 1 MB.
    Den andre typen enhet er NAND-teknologi - en tredimensjonal matrise har et lite celleareal, men relativt lang tilgang til en stor gruppe celler på en gang. Brukes til store mengder minne.Dette er minnet vi skal jobbe med.
    Men før det vil jeg gjerne snakke om en ulempe. Akkurat som alt har sin egen utløpsdato, har hukommelsen også en slitasjeressurs. I kappløpet om kapasitet og markedslederskap savner produsenter alltid en slik indikator som kvalitet, fordi... det er ikke forenlig med den høye prisen. Så, tilbake til slitasje, vil jeg merke at lagringstiden for informasjon ved bruk av MLC-enheter er omtrent 5 år, noe som er assosiert med akkumulering av irreversible endringer når ladningen endres. Hvis vi tar NAND-minne fra SLC-enheter, er de av høyere kvalitet og derfor dyrere. Det er verdt å merke seg at lagringstiden for informasjon i stor grad avhenger av temperatur, gammastråling og høyenergipartikler.
    Det ble sagt ovenfor at ulempen med kortet er det begrensede antallet omskrivingssykluser. Når vi bruker et filsystem til å administrere filer, må vi vite at slike systemer skriver data til ett sted, naturlig nok forbruker ressursen til det tildelte området, og til slutt gjør det ubrukelig og dermed reduserer kapasiteten. Denne typen minne bruker en NAND-kontroller, som skal fordele slitasje jevnt. Men for å redusere kostnadene for enheter, kan kontrolleren ikke brukes, og arbeidet vil bli utført av en programvare NAND-driver i operativsystemet. Etter denne oppdagelsen begynte mange selskaper å utvikle sine egne standarder for bærbare kort.

    Deretter går vi videre til å se på kartet.
    Secure Digital Memory Card (SD) er et minnekortformat utviklet for bruk primært i bærbare enheter. For å forstå funksjonen vil vi bruke spesifikasjonen som beskriver denne standarden og kalles SD-spesifikasjoner ver3.01.
    Det første vi trenger er å finne ut hvordan du jobber med dette kortet, hvordan du kobler det til osv. Først, la oss velge et kort. For eksperimenter tok jeg en 2 GB microSD, SDSC-kapasitetsstandard. Kortbussen kan operere ved hjelp av to protokoller: SD og SPI. Jeg vil merke meg at dette kortet er en slags modifikasjon av MMC-kortet, der (på SD-kortet) hovedoppmerksomheten ble gitt til sikkerhetssystemet. Derfor er driftsalgoritmen for SPI-protokollen den samme, og de er selvfølgelig enveiskompatible. Det vil si at vi kan sette inn en MMC i SD-kortsporet, men ikke omvendt.

    Figuren under viser koblingsskjemaet SD-kort SPI-protokoll .
    Dette grensesnittet lar deg utveksle data med høy hastighet ved å bruke et minimum antall mikrokontrollerpinner, som er utstyrt med en SPI-modul. Fra nå av vil vi begynne å bruke spesifikasjonen. Det første som interesserer oss er valget av modus. La oss se på finessene i fig. Nedenfor fra avsnitt 6.4.1.1 er et diagram over forsyningsspenningen og rekkefølgen for å sende kommandoen. Her kan du tydelig se at etter å ha slått på kortet, må du vente noen millisekunder (1ms + fra 0,1 til 35 ms (stigende)) for stabilisering. I løpet av denne tiden må 1 påføres CS, MOSI-linjen. Deretter oppstår en initialiseringsforsinkelse på maksimalt 1 ms når 74 pulser (sykluser) påføres CLK-inngangen, hvoretter CMD0-kommandoen må følge. La oss gå videre til kapittel 7 hvor handlingsrekkefølgen er tydelig beskrevet.

    Forsyningsspenningsdiagram

    SPI-protokollen velges etter å ha slått på strømmen og gitt CMD0-reset-kommandoen. Selve SD-kortet fungerer i SD-modus. Modusen settes inn hvis SC-signalet er 0 når CMD0-kommandoen gis. Ved bytte til SPI-modus vil kortet svare i R1-format (figur under). Svarformatet er en byte (avhengig av kommandoen, se tabell 7.3 i spesifikasjonen) med flagg som bestemmer kortets tilstand. De riktige svarene for oss vil være 1 (i tilfelle av CMD0-kommandoen) og 0 i alle andre tilfeller.
    1. bit – standby-modus
    2. – slette feil
    3. – ukjent lag
    4. – lagfeil
    5. – feil i slettesekvensen
    6. – adressefeil
    7. argumentfeil

    Under tilbakestillingsprosessen skal kortet svare med 0x01, som tilsvarer den første biten.

    Det er en klar rekkefølge i spesifikasjonen initialisering for SPI. Hvorfor brukes CMD8-kommandoen til å sjekke arbeidstilstanden til kortet, der en ganske komplisert verifiseringsalgoritme finner sted. Neste er CMD58-kommandoen for å bestemme korttypen SDSD eller SDHC og SDXC. Og også CMD41-kommandoen for å kjøre og sjekke initialisering. Det er en ganske komplisert initialiseringsprosess med kontroller, men jeg tror at for enkel dataregistrering kan en mer forenklet prosess brukes. I avsnitt 7.2.7. Det sies at i standby-modus er de eneste gyldige kommandoene for kortet CMD41, CMD8, CMD58, CMD59, samt for SD-minnekort (tykke 2,1 mm) CMD1, som er identisk med CMD41-kommandoen. I standarden anses denne kommandoen som forbudt for initialisering, og brukes utelukkende for å skille mellom 1,4 mm og 2,1 mm kort.
    La oss ta en enklere rute og bruke CMD1-kommandoen. Vi vil vise alt beskrevet ovenfor i koden i initialiseringsfunksjonen, men før det vil vi vurdere kommandoformatet. Hver instruksjon eller datablokk består av åtte bitbyte, som er justert til CLK-signalet. De. hver instruksjon er justert på en grense på 8 klokkesykluser. SPI-meldinger består av kommando, respons og data. All kommunikasjon styres av en mikrokontroller. Alle kommandoer er 6 byte lange. Sendingen starter med den første venstre biten.

    Figuren nedenfor viser kommandoformatet.


    Startbit - Enhver kommando starter fra 0.Den overførte biten er også alltid lik 1.
    Indeks – direkte overført kommando.
    Argument- For hver kommando er argumentet oppført i spesifikasjonstabellen.
    CRC kode redundanskontroll. Som standard er den deaktivert i SPI-modus. Derfor bruker vi den kun for CMD0-kommandoen, som sendes før du går inn i modusen og har en CRC-verdi på 0x95.
    Stopp litt - slutten av den overførte kommandoen.
    Så la oss begynne å skrive kode.
    La oss starte med de nødvendige 2 funksjonene: overføring og mottak av bytes.
    1. Overfør byten til kortet.
    void trans_byte_sd (usignerte tegndata) // sende en rekke biter
    {
    for (usignert char i=0;i<8;i++) //Iterer gjennom byten
    {
    if ((data&0×80)==0×00)//Hvis den mest signifikante biten = 0
    PORTB&=~_BV (PB3);//Sett MOSI (DI) -0
    ellers
    PORTB|=_BV (PB3);//1
    data=data<<1; // сдвиг влево
    PORTB|=_BV (PB5); //Puls eller strobe
    asm("nei"); //Pause på 1 slag
    PORTB&=~_BV (PB5);
    }
    }
    2. Mottak av byten av mikrokontrolleren.
    usignert tegn receive_byte_sd (ugyldig) // Returner svaret
    {
    usignerte tegndata = 0; // initialiser matrisen
    for (usignert char i=0; i<8; i++)
    {
    PORTB|=_BV (PB5); //Pulskant
    data=data<<1; // Skift til venstre
    if ((PINB&_BV (PB4))!=0×00) // Hvis pin-status er 1
    data=data|0×01;
    PORTB&=~_BV (PB5); //0
    asm("nei");
    }
    returnere data; // Returner svaret
    }

    Fra de grunnleggende funksjonene beskrevet ovenfor, vil vi begynne å skrive ytterligere kode. Deretter vil vi skrive kommandooverføringsfunksjonen. Her vil jeg trekke oppmerksomheten din til det faktum at du kan sende alle 5 argumentene: direkte selve kommandoen og 4 argumenter som er ansvarlige for adressen til minnecellene på selve kortet. Når det gjelder 6. byte, da CRC når du går inn i SPI-modus er deaktivert (som standard) og verdien er permanent satt til 0x95, som bare brukes for CMD0 når kortet ikke er i modus. Du kan aktivere kodekontroll ved å bruke CMD58-kommandoen. For eksperimentering sender jeg to argumenter.

    3. Overføring av kommando.
    usignert char comand_sd (char CMD, char arg) /*gi kommandoen og adressen vi har tilgang til og returner svaret*/
    {
    long int i=0; // variabel for telleren
    usignert char r1; // kortsvar
    trans_byte_sd(CMD); // team
    trans_byte_sd(0×00);
    trans_byte_sd(0×00);
    trans_byte_sd(arg); // adresseoverføring
    trans_byte_sd(0×00);
    trans_byte_sd(0×95); // Send CRC
    /* Etter å ha overført kommandoen venter vi på svar i R1-format. Hver kommando har sitt eget svar */
    /* Loop for å vente på svar innen en viss tid */
    gjøre
    {
    r1=receive_byte_sd();
    i++;
    ) mens (((r1&0×80)!=0×00)&&(i<0xffff)); /* Så lenge den mest signifikante biten av byten ikke er 0 og i ikke overstiger 65 535 klokkesykluser */
    retur r1; // Returner svaret
    }
    4. Og initialisering av kortet.

    Nå kan vi initialisere kartet. Programmet er kort beskrevet som følger: det første du må gjøre er å bytte kortet til SPI-modus. Når strømmen kobles til, er kortet satt til SD-modus. For å velge SPI-modus brukes en logisk 0 på CS-inngangen, samtidig sendes kommandoen for å tilbakestille CMD0 og initialisere CMD1 til inngangen til MOSI-kortet. Vær oppmerksom på at kommandoen begynner med heksadesimal 0x40, som du må legge til CMD-kommandonummeret i heksadesimal.

    usignert char spi_card_init (ugyldig)//-funksjonen returnerer respons
    {
    usignert char r1; // variabel for å motta svaret
    long int i =0; // variabel for telleren
    _forsinkelse_ms(10); // en liten forsinkelse for å stabilisere spenningen.
    PORTB|=_BV (PB1); //CS, satt til 1, når du sender inn klokkesykluser
    PORTB|=_BV (PB3); //kommandolinje - 1 MOSI (DI)
    for (usignert char i=0; i<80;i++) // sende mer enn 74 pulser
    {
    PORTB|=_BV (PB5); //CLK - 1
    asm("nei"); //utsett én klokke
    PORTB&=~_BV (PB5); //CLK - 0
    }
    PORTB&=~_BV (PB1); /* betingelse for å gå inn i SPI-modus CS-linje skal være lik 0 */
    r1=comand_sd (0×40,0×00); // CMD0=0×40, adressen spiller ingen rolle
    if (r1!=0×01) returner 4;//du kan angi alle feilkoder
    trans_byte_sd(0xff); /* send en strobe, en slags pause før du mottar et svar */
    gjøre // syklus for å motta et svar fra kortet
    {
    r1=comand_sd (0×41,0×00); /* send initialiseringskommandoen */
    trans_byte_sd(0xff); // pause
    i++; // disk
    ) mens ((r1!= 0)&&(i<65535)); /*til et 0-svar mottas og antall sykluser ikke overstiger 0xffff */
    if (i>=0xffff) returner 5; /* returnerer en feil hvis avstemningstiden har overskredet */
    returner 0; //Returner 0 hvis initialiseringen er vellykket
    }

    Det neste viktige punktet er at spesifikasjonen sier at informasjon overføres i blokker på 512 biter, og hvis SDSC-kortet er som i vårt tilfelle, kan blokklengden settes fra 1 til 512 biter ved hjelp av CMD16-kommandoen. Standard er 512 bits. Deretter beskriver vi to funksjoner for å motta og sende blokker. Spesifikasjonen inneholder blokkdiagrammer, basert på hvilke vi skal skrive koden.

    Overføre en blokk med informasjon til kortet.

    CMD24-kommandoen er ansvarlig for å overføre den ENESTE blokken. Etter å ha gitt kommandoen venter vi på svar Dette etterfølges av en startbyte, som forbereder kortkontrolleren til å motta informasjon, på slutten svarer kortet med en byte om overføringsstatus, som er beskrevet i kapittel 7.3. 3.1. De. riktig svar skal være = 5. Vi venter også på at bussen blir ledig for videre overføring.

    Overfør statustilbakemeldingsbyte.

    Avsnitt 7.3.3.2 beskriver formatet til den overførte blokken
    usignert char receive_block_sd (char* block, char arg)/* sende arrayet for registrering av data og adressen som vi har tilgang til */
    {
    long int i = 0;
    usignert char r1;
    r1=comand_sd(0X51,arg);//CMD17
    if (r1!=0×00) returner 5;//Avslutt hvis svaret ikke er 0×00
    trans_byte_sd(0xff);
    gjøre //Vent til datapakken starter
    {
    r1=receive_byte_sd();
    i++;
    ) mens ((r1!= 0xfe)&&(i<65535));
    if (i>=0xffff) returner 5;
    for (int i=0;i<512;i=i+1) //motta data
    blokk[i] = mottaksbyte_sd();
    motta_byte_sd(); //CRC byte
    motta_byte_sd(); //CRC byte
    returner 0;
    }

    Før du bruker programmet, la oss se på maskinvaren. Som vi sa ovenfor, er kortet kompatibelt med mikrokontrolleren i SPI-modus. La oss merke oss følgende nyanser ved å jobbe med kartet:
    1. Sammenkobling av logiske nivåer er nødvendig for forskjellige forsyningsspenninger til SD-kortet og AVR-mikrokontrolleren. Du kan bruke en resistiv spenningsdeler som er lineær, dvs. Utgangsspenningen avhenger av inngangsspenningen. Eller du kan ha en parallell parametrisk spenningsstabilisator på en zenerdiode, det samme som det første alternativet, bare i den nedre armen brukes en zenerdiode, som er en ikke-lineær deler og overvåker referansespenningen på grunn av dens egenskaper, når inngangen spenningen øker, det reduserer den indre motstanden, og omvendt.
    Jeg brukte det andre alternativet. I kretsen nedenfor, på signallinjen, er motstandene ballast (strømbegrensere), en spenning på 4,5 - 5 V leveres til inngangen til deleren, og utgangen fjernes fra den nedre armen til deleren.Strømbegrensere er nødvendige for å beskytte kortet og andre eksterne enheter i tilfelle mikrokontrollerfeil. Med en velfungerende enhet er de ikke nødvendige.

    Merk at MISO-linjen ikke trenger å forhandles pga Det fungerer bare i én retning fra kortet til mikrokontrolleren.
    2. Andre punkt, jeg bruker ikke korttilgjengelighet og skrivebeskyttelsessjekker. Noen mennesker har disse kontaktene i spor, noen har ikke.
    3. Det siste punktet er mat. Enten leverer DU 3,3 volt til hele kretsen, inkludert mikrokontrolleren, eller så setter du en deler ved inngangen til kretsen, noe som ikke er særlig pålitelig. Eller en 3,3 volt stabilisator, som jeg gjorde på brikken LP2980 . Et viktig poeng her er den elektrolytiske (tantal) kondensatoren, som beskytter mikrokontrolleren mot å bli tilbakestilt under spenningsfall.
    Nedenfor er programmet og resultatet.Som alltid prøver jeg å bruke ett program og endre det hele tiden. Denne koden er hentet fra artikkel nr. 5 (syv-segmentindikator).

    #inkludere
    #inkludere
    #inkludere
    #inkludere
    //makroer for å jobbe med indikatoren
    #definer en 128
    #define b 32
    #definer fra 8
    #define d 2
    #define e 1
    #define f 64
    #define g 16
    #define dp 4

    // Variabler

    char block =();//buffer for å skrive/lese data til kortet
    kort usignert int j, k = 0; //i avbruddsmakroen
    usignert char Slot; // Matrise med tall som skal vises på indikatoren

    //Erklære funksjoner

    void trans_byte_sd (usignerte tegndata);// byteoverføringsfunksjon
    usignert char receive_byte_sd (ugyldig); //Byte-mottaksfunksjon
    usignert char comand_sd (char, char); // kommandooverføringsfunksjon
    usignert char spi_card_init (ugyldig); //Initialiseringsfunksjon for minnekort
    usignert char receive_block_sd (char* block, char arg); //Blokker mottaksfunksjon
    usignert char trans_block_sd (char* block, char arg); //Blokkér overføringsfunksjon
    // Indikatorinitialisering
    void Slot_init()
    {…………………….};
    // Variabler for å vise tall
    røye Elem1, Elem2, Elem3;
    // Utgang til indikator
    void Display (flytende i)
    { …………………………... }
    int main (ugyldig) //begynn grunnlaget for programmet
    {
    DDRB = 0x2A; //0010 1010 – PB1, PB3, PB5
    DDRD = 0xff; //alle portpinner er utganger
    PORTD = 0×00; //sett til 0
    PORTB |= 0хdb; //1101 1011 (PB0,1,3,4,6,7)
    slot_init();
    sei(); // eller SREG |= (1<< 7); разрешить общее прерывание
    //initialiser timer T0
    TIMSK = (1</*Aktiver flagg for tellertimer T0 overløp*/
    TCCR0 = (0< //1000000/8 = 125000
    usignert char temp;
    int i;
    for (i=0;i<512;i=i+1)
    blokk[i]= i; //skriv til buffer
    spi_card_init(); //initialisering
    trans_blokk_sd(blokk,0×04); //send data til kortet
    //Tilbakestill bufferen til null
    for (int i=0;i<512;i=i+1)
    blokk[i]=0;
    // Les data fra kortet
    receive_block_sd(blokk, 0×04); ;//Byte-mottaksfunksjon
    for (int i=0;i<512;i=i+1)
    {
    røye otv;
    otv = blokk[i];
    Display(otv);
    _forsinkelse_ms(100);
    }
    //Skriv til minneadresse 0
    for (int i=0;i<512;i=i+1)
    blokk[i]=0;
    usignert char comand_sd (char,0×00); //kommandooverføringsfunksjon
    trans_blokk_sd(blokk,0×04); //send data til kortet
    }
    //Utgang til indikator
    ISR (TIMER0_OVF_vect)
    { ……………. }

    Et viktig poeng er timeouts. Det er viktig å overvåke tiden det tar å lese en post og slette et kort, siden mikrokontrolleren kan fryse mens den venter på svar fra kortet. Spesifikasjonen beskriver tydelig korttidsavbrudd. Kortet er inaktivt i 5 ms, hvoretter det går i strømsparingsmodus, der følgende kommandoer er gyldige: CMD0, CMD1, CMD41 og CMD58. Derfor, når tomgangsgrensen overskrides, sender vi CMD1, svaret og fortsetter å jobbe med kortet.
    Nedenfor er to skjermbilder fra programmet WinHex, som vi kan se innholdet i minneceller med. Programmet fungerer som følger: Vi skriver data til bufferen, sender dem til kortet, tilbakestiller bufferen, leser dataene fra kortet inn i bufferen og viser dem på displayet, og sørger derved for at dataene blir overført til kortet . Vi ser på innholdet på kortet, tilbakestiller bufferen, skriver 0 til kortet og åpner innholdet på kortet igjen, og forsikrer oss dermed om at programmet og kretsen fungerer. Som alltid, ikke glem de små tingene, som å ikke få nok loddetinn, ikke ha store sprekker i sporene osv., som kan ta brorparten av tiden. Derfor, hvis du har et oscilloskop for hånden, sørg for å bruke det til oppsett. IArtikkel nr. 24Jeg ga et lite eksempel på diagnostisering av et kort i alle stadier av operasjonen.vi møtesfuktighets- og temperatursensorDHT11. Deretter vil vi begynne å registrere data (temperatur og fuktighet) til en tekstfil, en slags database. Det er alt for nå. Ha det alle sammen.