tmp commit
This commit is contained in:
parent
ee2ee8469e
commit
30afd8a68e
2
Makefile
2
Makefile
|
@ -63,7 +63,7 @@ else
|
|||
RUSTSBI = ./bootloader/SBI/sbi-qemu
|
||||
endif
|
||||
|
||||
TOOLPREFIX := riscv64-unknown-elf-
|
||||
TOOLPREFIX := riscv64-linux-gnu-
|
||||
# TOOLPREFIX := riscv64-linux-gnu-
|
||||
CC = $(TOOLPREFIX)gcc
|
||||
AS = $(TOOLPREFIX)gas
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef _SDCARD_H
|
||||
#define _SDCARD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Card Specific Data: CSD Register
|
||||
*/
|
||||
typedef struct {
|
||||
uint8 CSDStruct; /*!< CSD structure */
|
||||
uint8 SysSpecVersion; /*!< System specification version */
|
||||
uint8 Reserved1; /*!< Reserved */
|
||||
uint8 TAAC; /*!< Data read access-time 1 */
|
||||
uint8 NSAC; /*!< Data read access-time 2 in CLK cycles */
|
||||
uint8 MaxBusClkFrec; /*!< Max. bus clock frequency */
|
||||
uint16 CardComdClasses; /*!< Card command classes */
|
||||
uint8 RdBlockLen; /*!< Max. read data block length */
|
||||
uint8 PartBlockRead; /*!< Partial blocks for read allowed */
|
||||
uint8 WrBlockMisalign; /*!< Write block misalignment */
|
||||
uint8 RdBlockMisalign; /*!< Read block misalignment */
|
||||
uint8 DSRImpl; /*!< DSR implemented */
|
||||
uint8 Reserved2; /*!< Reserved */
|
||||
uint32 DeviceSize; /*!< Device Size */
|
||||
uint8 MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
|
||||
uint8 MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
|
||||
uint8 MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
|
||||
uint8 MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
|
||||
uint8 DeviceSizeMul; /*!< Device size multiplier */
|
||||
uint8 EraseGrSize; /*!< Erase group size */
|
||||
uint8 EraseGrMul; /*!< Erase group size multiplier */
|
||||
uint8 WrProtectGrSize; /*!< Write protect group size */
|
||||
uint8 WrProtectGrEnable; /*!< Write protect group enable */
|
||||
uint8 ManDeflECC; /*!< Manufacturer default ECC */
|
||||
uint8 WrSpeedFact; /*!< Write speed factor */
|
||||
uint8 MaxWrBlockLen; /*!< Max. write data block length */
|
||||
uint8 WriteBlockPaPartial; /*!< Partial blocks for write allowed */
|
||||
uint8 Reserved3; /*!< Reserded */
|
||||
uint8 ContentProtectAppli; /*!< Content protection application */
|
||||
uint8 FileFormatGrouop; /*!< File format group */
|
||||
uint8 CopyFlag; /*!< Copy flag (OTP) */
|
||||
uint8 PermWrProtect; /*!< Permanent write protection */
|
||||
uint8 TempWrProtect; /*!< Temporary write protection */
|
||||
uint8 FileFormat; /*!< File Format */
|
||||
uint8 ECC; /*!< ECC code */
|
||||
uint8 CSD_CRC; /*!< CSD CRC */
|
||||
uint8 Reserved4; /*!< always 1*/
|
||||
} SD_CSD;
|
||||
|
||||
/**
|
||||
* @brief Card Identification Data: CID Register
|
||||
*/
|
||||
typedef struct {
|
||||
uint8 ManufacturerID; /*!< ManufacturerID */
|
||||
uint16 OEM_AppliID; /*!< OEM/Application ID */
|
||||
uint32 ProdName1; /*!< Product Name part1 */
|
||||
uint8 ProdName2; /*!< Product Name part2*/
|
||||
uint8 ProdRev; /*!< Product Revision */
|
||||
uint32 ProdSN; /*!< Product Serial Number */
|
||||
uint8 Reserved1; /*!< Reserved1 */
|
||||
uint16 ManufactDate; /*!< Manufacturing Date */
|
||||
uint8 CID_CRC; /*!< CID CRC */
|
||||
uint8 Reserved2; /*!< always 1 */
|
||||
} SD_CID;
|
||||
|
||||
/**
|
||||
* @brief SD Card information
|
||||
*/
|
||||
typedef struct {
|
||||
SD_CSD SD_csd;
|
||||
SD_CID SD_cid;
|
||||
uint64 CardCapacity; /*!< Card Capacity */
|
||||
uint32 CardBlockSize; /*!< Card Block Size */
|
||||
} SD_CardInfo;
|
||||
|
||||
extern SD_CardInfo cardinfo;
|
||||
|
||||
uint8 sd_init(void);
|
||||
void sdcard_init(void);
|
||||
uint8 sd_read_sector(uint8 *data_buff, uint32 sector, uint32 count);
|
||||
uint8 sd_write_sector(uint8 *data_buff, uint32 sector, uint32 count);
|
||||
uint8 sd_read_sector_dma(uint8 *data_buff, uint32 sector, uint32 count);
|
||||
uint8 sd_write_sector_dma(uint8 *data_buff, uint32 sector, uint32 count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
//
|
||||
// Created by lumin on 2020/11/2.
|
||||
//
|
||||
|
||||
#ifndef LAB8_SDCARD_H
|
||||
#define LAB8_SDCARD_H
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
/*
|
||||
* SD Card Commands
|
||||
* @brief Commands: CMDxx = CMD-number | 0x40
|
||||
*/
|
||||
#define SD_CMD_SIGN (0x40)
|
||||
#define SD_CMD0 0 // chip reset
|
||||
#define SD_CMD8 8 // voltage negotiation
|
||||
#define SD_CMD9 9 // read CSD register
|
||||
#define SD_CMD10 10 // read CID register
|
||||
#define SD_CMD12 12 // end multiple continuous sector read
|
||||
#define SD_CMD17 17 // start single sector read
|
||||
#define SD_CMD18 18 // start multiple continuous sector read and send start sector
|
||||
#define SD_ACMD23 23 // start multiple continuous sector write and send sector count
|
||||
#define SD_CMD24 24 // start single sector write
|
||||
#define SD_CMD25 25 // start multiple continuous sector write and send start sector
|
||||
#define SD_ACMD41 41 // capacity mode set
|
||||
#define SD_CMD55 55 // ACMD prefix
|
||||
#define SD_CMD58 58 // read CCS(card capacity status)
|
||||
|
||||
#define SD_INIT_MODE_RESULT_OK (0x01)
|
||||
#define SD_TRANS_MODE_RESULT_OK (0x00)
|
||||
#define SD_START_DATA_READ_RESPONSE (0xFE)
|
||||
#define SD_START_DATA_SINGLE_BLOCK_WRITE_TOKEN (0xFE)
|
||||
#define SD_START_DATA_MULTIPLE_BLOCK_WRITE_TOKEN (0xFC)
|
||||
|
||||
/**
|
||||
* CMD frame format
|
||||
* | CRC | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | CMD |
|
||||
* | byte 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 |
|
||||
*/
|
||||
#define SD_CMD_CMD_BIT 0
|
||||
#define SD_CMD_ARG_MSB0 1
|
||||
#define SD_CMD_ARG_MSB1 2
|
||||
#define SD_CMD_ARG_MSB2 3
|
||||
#define SD_CMD_ARG_MSB3 4
|
||||
#define SD_CMD_CRC_BIT 5
|
||||
#define SD_CMD_FRAME_SIZE 6
|
||||
|
||||
#define SD_EMPTY_FILL (0xFF)
|
||||
|
||||
#define SD_R3_RESPONSE_REST_LENGTH 4
|
||||
#define SD_R7_RESPONSE_REST_LENGTH 4
|
||||
|
||||
// SD card here uses SPI mode, pin
|
||||
// names also inherit from it.
|
||||
typedef struct
|
||||
{
|
||||
int mosi_pin; // pin num of Master Out Slave In
|
||||
int miso_pin; // pin num of Master In Slave Out
|
||||
int sclk_pin; // pin num of SPI Clock
|
||||
int cs_pin; // pin num of Chip Selector
|
||||
int cs_gpio_num;// what is this..?
|
||||
} sdcard_hardware_pin_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t CSDStruct; /*!< CSD structure */
|
||||
uint8_t SysSpecVersion; /*!< System specification version */
|
||||
uint8_t Reserved1; /*!< Reserved */
|
||||
uint8_t TAAC; /*!< Data read access-time 1 */
|
||||
uint8_t NSAC; /*!< Data read access-time 2 in CLK cycles */
|
||||
uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */
|
||||
uint16_t CardComdClasses; /*!< Card command classes */
|
||||
uint8_t RdBlockLen; /*!< Max. read data block length */
|
||||
uint8_t PartBlockRead; /*!< Partial blocks for read allowed */
|
||||
uint8_t WrBlockMisalign; /*!< Write block misalignment */
|
||||
uint8_t RdBlockMisalign; /*!< Read block misalignment */
|
||||
uint8_t DSRImpl; /*!< DSR implemented */
|
||||
uint8_t Reserved2; /*!< Reserved */
|
||||
uint32_t DeviceSize; /*!< Device Size */
|
||||
uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */
|
||||
uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */
|
||||
uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */
|
||||
uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */
|
||||
uint8_t DeviceSizeMul; /*!< Device size multiplier */
|
||||
uint8_t EraseGrSize; /*!< Erase group size */
|
||||
uint8_t EraseGrMul; /*!< Erase group size multiplier */
|
||||
uint8_t WrProtectGrSize; /*!< Write protect group size */
|
||||
uint8_t WrProtectGrEnable; /*!< Write protect group enable */
|
||||
uint8_t ManDeflECC; /*!< Manufacturer default ECC */
|
||||
uint8_t WrSpeedFact; /*!< Write speed factor */
|
||||
uint8_t MaxWrBlockLen; /*!< Max. write data block length */
|
||||
uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */
|
||||
uint8_t Reserved3; /*!< Reserded */
|
||||
uint8_t ContentProtectAppli; /*!< Content protection application */
|
||||
uint8_t FileFormatGrouop; /*!< File format group */
|
||||
uint8_t CopyFlag; /*!< Copy flag (OTP) */
|
||||
uint8_t PermWrProtect; /*!< Permanent write protection */
|
||||
uint8_t TempWrProtect; /*!< Temporary write protection */
|
||||
uint8_t FileFormat; /*!< File Format */
|
||||
uint8_t ECC; /*!< ECC code */
|
||||
uint8_t CSD_CRC; /*!< CSD CRC */
|
||||
uint8_t Reserved4; /*!< always 1*/
|
||||
uint8_t CSizeMlut; /*!< */
|
||||
} SD_CSD;
|
||||
|
||||
/**
|
||||
* @brief Card Identification Data: CID Register
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ManufacturerID; /*!< ManufacturerID */
|
||||
uint16_t OEM_AppliID; /*!< OEM/Application ID */
|
||||
uint32_t ProdName1; /*!< Product Name part1 */
|
||||
uint8_t ProdName2; /*!< Product Name part2*/
|
||||
uint8_t ProdRev; /*!< Product Revision */
|
||||
uint32_t ProdSN; /*!< Product Serial Number */
|
||||
uint8_t Reserved1; /*!< Reserved1 */
|
||||
uint16_t ManufactDate; /*!< Manufacturing Date */
|
||||
uint8_t CID_CRC; /*!< CID CRC */
|
||||
uint8_t Reserved2; /*!< always 1 */
|
||||
} SD_CID;
|
||||
|
||||
/**
|
||||
* @brief SD Card information
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
SD_CSD SD_csd;
|
||||
SD_CID SD_cid;
|
||||
uint64_t CardCapacity; /*!< Card Capacity */
|
||||
uint32_t CardBlockSize; /*!< Card Block Size */
|
||||
uint8_t active;
|
||||
} SD_CardInfo;
|
||||
|
||||
extern SD_CardInfo cardinfo;
|
||||
|
||||
/**
|
||||
* Initialize the SD Card
|
||||
*/
|
||||
void sd_init();
|
||||
|
||||
/**
|
||||
* Synchronously read single/multiple sector(s) from SD card
|
||||
*
|
||||
* @param data_buff pointer to the buffer that receives the data read from the SD.
|
||||
* @param sector SD's internal address to read from.
|
||||
* @param count count of sectors to be read
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
uint8_t sd_read_sector(uint8_t *data_buff, uint32_t sector, uint32_t count);
|
||||
|
||||
/**
|
||||
* Synchronously write single/multiple sector(s) from SD card
|
||||
*
|
||||
* @param data_buff pointer to the buffer to be written to the SD.
|
||||
* @param sector SD's internal address to write to.
|
||||
* @param count count of sectors to be read
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
uint8_t sd_write_sector(uint8_t *data_buff, uint32_t sector, uint32_t count);
|
||||
|
||||
#endif //LAB8_SDCARD_H
|
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// Created by lumin on 2020/11/2.
|
||||
//
|
||||
|
||||
#ifndef LAB8_SPI_H
|
||||
#define LAB8_SPI_H
|
||||
|
||||
#include <defs.h>
|
||||
#include <io.h>
|
||||
|
||||
#define SPI01_WORK_MODE_OFFSET 6
|
||||
#define SPI012_TRANSFER_MODE_OFFSET 8
|
||||
#define SPI01_DATA_BIT_LENGTH_OFFSET 16
|
||||
#define SPI01_FRAME_FORMAT_OFFSET 21
|
||||
|
||||
#define SPI3_WORK_MODE_OFFSET 8
|
||||
#define SPI3_TRANSFER_MODE_OFFSET 10
|
||||
#define SPI3_DATA_BIT_LENGTH_OFFSET 0
|
||||
#define SPI3_FRAME_FORMAT_OFFSET 22
|
||||
|
||||
#define SPI_DATA_BIT_LENGTH_BIT 5
|
||||
#define SPI_MIN_DATA_BIT_LENGTH 4
|
||||
#define SPI_MAX_DATA_BIT_LENGTH (1 << SPI_DATA_BIT_LENGTH_BIT)
|
||||
|
||||
#define SPI_BAUDRATE_DEFAULT_VAL (0x14)
|
||||
#define SPI_INTERRUPT_DISABLE (0x00)
|
||||
#define SPI_DMACR_DEFAULT_VAL (0x00)
|
||||
#define SPI_DMATDLR_DEFAULT_VAL (0x00)
|
||||
#define SPI_DMARDLR_DEFAULT_VAL (0x00)
|
||||
#define SPI_SLAVE_DISABLE (0x00)
|
||||
#define SPI_MASTER_DISABLE (0x00)
|
||||
#define SPI_MASTER_ENABLE (0x01)
|
||||
#define SPI_TMOD_DEFAULT_VAL 0
|
||||
|
||||
#define SPI_FIFO_CAPCITY_IN_BYTE (32)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* SPI Control Register 0 (0x00)*/
|
||||
volatile uint32_t ctrlr0;
|
||||
/* SPI Control Register 1 (0x04)*/
|
||||
volatile uint32_t ctrlr1;
|
||||
/* SPI Enable Register (0x08)*/
|
||||
volatile uint32_t ssienr;
|
||||
/* SPI Microwire Control Register (0x0c)*/
|
||||
volatile uint32_t mwcr;
|
||||
/* SPI Slave Enable Register (0x10)*/
|
||||
volatile uint32_t ser;
|
||||
/* SPI Baud Rate Select (0x14)*/
|
||||
volatile uint32_t baudr;
|
||||
/* SPI Transmit FIFO Threshold Level (0x18)*/
|
||||
volatile uint32_t txftlr;
|
||||
/* SPI Receive FIFO Threshold Level (0x1c)*/
|
||||
volatile uint32_t rxftlr;
|
||||
/* SPI Transmit FIFO Level Register (0x20)*/
|
||||
volatile uint32_t txflr;
|
||||
/* SPI Receive FIFO Level Register (0x24)*/
|
||||
volatile uint32_t rxflr;
|
||||
/* SPI Status Register (0x28)*/
|
||||
volatile uint32_t sr;
|
||||
/* SPI Interrupt Mask Register (0x2c)*/
|
||||
volatile uint32_t imr;
|
||||
/* SPI Interrupt Status Register (0x30)*/
|
||||
volatile uint32_t isr;
|
||||
/* SPI Raw Interrupt Status Register (0x34)*/
|
||||
volatile uint32_t risr;
|
||||
/* SPI Transmit FIFO Overflow Interrupt Clear Register (0x38)*/
|
||||
volatile uint32_t txoicr;
|
||||
/* SPI Receive FIFO Overflow Interrupt Clear Register (0x3c)*/
|
||||
volatile uint32_t rxoicr;
|
||||
/* SPI Receive FIFO Underflow Interrupt Clear Register (0x40)*/
|
||||
volatile uint32_t rxuicr;
|
||||
/* SPI Multi-Master Interrupt Clear Register (0x44)*/
|
||||
volatile uint32_t msticr;
|
||||
/* SPI Interrupt Clear Register (0x48)*/
|
||||
volatile uint32_t icr;
|
||||
/* SPI DMA Control Register (0x4c)*/
|
||||
volatile uint32_t dmacr;
|
||||
/* SPI DMA Transmit Data Level (0x50)*/
|
||||
volatile uint32_t dmatdlr;
|
||||
/* SPI DMA Receive Data Level (0x54)*/
|
||||
volatile uint32_t dmardlr;
|
||||
/* SPI Identification Register (0x58)*/
|
||||
volatile uint32_t idr;
|
||||
/* SPI DWC_ssi component version (0x5c)*/
|
||||
volatile uint32_t ssic_version_id;
|
||||
/* SPI Data Register 0-36 (0x60 -- 0xec)*/
|
||||
volatile uint32_t dr[36];
|
||||
/* SPI RX Sample Delay Register (0xf0)*/
|
||||
volatile uint32_t rx_sample_delay;
|
||||
/* SPI SPI Control Register (0xf4)*/
|
||||
volatile uint32_t spi_ctrlr0;
|
||||
/* reserved (0xf8)*/
|
||||
volatile uint32_t resv;
|
||||
/* SPI XIP Mode bits (0xfc)*/
|
||||
volatile uint32_t xip_mode_bits;
|
||||
/* SPI XIP INCR transfer opcode (0x100)*/
|
||||
volatile uint32_t xip_incr_inst;
|
||||
/* SPI XIP WRAP transfer opcode (0x104)*/
|
||||
volatile uint32_t xip_wrap_inst;
|
||||
/* SPI XIP Control Register (0x108)*/
|
||||
volatile uint32_t xip_ctrl;
|
||||
/* SPI XIP Slave Enable Register (0x10c)*/
|
||||
volatile uint32_t xip_ser;
|
||||
/* SPI XIP Receive FIFO Overflow Interrupt Clear Register (0x110)*/
|
||||
volatile uint32_t xrxoicr;
|
||||
/* SPI XIP time out register for continuous transfers (0x114)*/
|
||||
volatile uint32_t xip_cnt_time_out;
|
||||
volatile uint32_t endian;
|
||||
} __attribute__((packed, aligned(4))) spi_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_DEVICE_0,
|
||||
SPI_DEVICE_1,
|
||||
SPI_DEVICE_2,
|
||||
SPI_DEVICE_3,
|
||||
SPI_DEVICE_MAX,
|
||||
} spi_device_num_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_WORK_MODE_0,
|
||||
SPI_WORK_MODE_1,
|
||||
SPI_WORK_MODE_2,
|
||||
SPI_WORK_MODE_3,
|
||||
} spi_work_mode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_FF_STANDARD,
|
||||
SPI_FF_DUAL,
|
||||
SPI_FF_QUAD,
|
||||
SPI_FF_OCTAL,
|
||||
} spi_frame_format_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_TMODE_TRANS_RECV,
|
||||
SPI_TMODE_TRANS,
|
||||
SPI_TMODE_RECV,
|
||||
SPI_TMODE_EEROM,
|
||||
} spi_transfer_mode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPI_CHIP_SELECT_0,
|
||||
SPI_CHIP_SELECT_1,
|
||||
SPI_CHIP_SELECT_2,
|
||||
SPI_CHIP_SELECT_3,
|
||||
SPI_CHIP_SELECT_MAX,
|
||||
} spi_chip_select_t;
|
||||
|
||||
extern volatile spi_t *const spi[4];
|
||||
|
||||
/**
|
||||
* @brief Set spi configuration
|
||||
*
|
||||
* @param[in] spi_num Spi bus number
|
||||
* @param[in] mode Spi mode
|
||||
* @param[in] frame_format Spi frame format
|
||||
* @param[in] data_bit_length Spi data bit length
|
||||
* @param[in] endian 0:little-endian 1:big-endian
|
||||
*
|
||||
* @return Void
|
||||
*/
|
||||
void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
|
||||
size_t data_bit_length, uint32_t endian);
|
||||
|
||||
/**
|
||||
* @brief Spi send data
|
||||
*
|
||||
* @param[in] spi_num Spi bus number
|
||||
* @param[in] slave Spi chip select
|
||||
* @param[in] cmd_buff Spi command buffer point
|
||||
* @param[in] cmd_len Spi command length
|
||||
* @param[in] tx_buff Spi transmit buffer point
|
||||
* @param[in] tx_len Spi transmit buffer length
|
||||
*
|
||||
* @return Result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t slave, const uint8_t *tx_buff, size_t tx_len);
|
||||
|
||||
/**
|
||||
* @brief Spi receive data
|
||||
*
|
||||
* @param[in] spi_num Spi bus number
|
||||
* @param[in] chip_select Spi chip select
|
||||
* @param[in] rx_buff Spi receive buffer point
|
||||
* @param[in] rx_len Spi receive buffer length
|
||||
*
|
||||
* @return Result
|
||||
* - 0 Success
|
||||
* - Other Fail
|
||||
*/
|
||||
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, uint8_t *rx_buff, size_t rx_len);
|
||||
|
||||
/**
|
||||
* @brief Spi normal send by dma
|
||||
*
|
||||
* @param[in] spi_num Spi bus number
|
||||
* @param[in] spi_clk Spi clock rate
|
||||
*
|
||||
* @return The real spi clock rate
|
||||
*/
|
||||
uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk);
|
||||
|
||||
#endif //LAB8_SPI_H
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef __VM_H
|
||||
#define __VM_H
|
||||
|
||||
#include "types.h"
|
||||
#include "riscv.h"
|
||||
|
||||
void kvminit(void);
|
||||
void kvminithart(void);
|
||||
uint64 kvmpa(uint64);
|
||||
void kvmmap(uint64, uint64, uint64, int);
|
||||
int mappages(pagetable_t, uint64, uint64, uint64, int);
|
||||
pagetable_t uvmcreate(void);
|
||||
void uvminit(pagetable_t, uchar *, uint);
|
||||
uint64 uvmalloc(pagetable_t, uint64, uint64);
|
||||
uint64 uvmdealloc(pagetable_t, uint64, uint64);
|
||||
int uvmcopy(pagetable_t, pagetable_t, uint64);
|
||||
void uvmfree(pagetable_t, uint64);
|
||||
void uvmunmap(pagetable_t, uint64, uint64, int);
|
||||
void uvmclear(pagetable_t, uint64);
|
||||
uint64 walkaddr(pagetable_t, uint64);
|
||||
int copyout(pagetable_t, uint64, char *, uint64);
|
||||
int copyin(pagetable_t, char *, uint64, uint64);
|
||||
int copyinstr(pagetable_t, char *, uint64, uint64);
|
||||
|
||||
#endif
|
|
@ -36,12 +36,12 @@ main(unsigned long hartid, unsigned long dtb_pa)
|
|||
timerinit(); // set up timer interrupt handler
|
||||
procinit();
|
||||
#ifndef QEMU
|
||||
device_init(dtb_pa, hartid);
|
||||
//device_init(dtb_pa, hartid);
|
||||
fpioa_pin_init();
|
||||
// sdcard_init();
|
||||
sdcard_init();
|
||||
|
||||
test_proc_init(8); // test porc init
|
||||
// test_sdcard();
|
||||
//test_proc_init(8); // test porc init
|
||||
test_sdcard();
|
||||
// test_kalloc(); // test kalloc
|
||||
// test_vm(hartid); // test kernel pagetable
|
||||
#else
|
||||
|
|
|
@ -0,0 +1,527 @@
|
|||
#include "include/types.h"
|
||||
#include "include/sdcard.h"
|
||||
#include "include/spi.h"
|
||||
#include "include/riscv.h"
|
||||
#include "include/gpiohs.h"
|
||||
#include "include/defs.h"
|
||||
/*
|
||||
* @brief Start Data tokens:
|
||||
* Tokens (necessary because at nop/idle (and CS active) only 0xff is
|
||||
* on the data/command line)
|
||||
*/
|
||||
#define SD_START_DATA_SINGLE_BLOCK_READ 0xFE /*!< Data token start byte, Start Single Block Read */
|
||||
#define SD_START_DATA_MULTIPLE_BLOCK_READ 0xFE /*!< Data token start byte, Start Multiple Block Read */
|
||||
#define SD_START_DATA_SINGLE_BLOCK_WRITE 0xFE /*!< Data token start byte, Start Single Block Write */
|
||||
#define SD_START_DATA_MULTIPLE_BLOCK_WRITE 0xFC /*!< Data token start byte, Start Multiple Block Write */
|
||||
|
||||
/*
|
||||
* @brief Commands: CMDxx = CMD-number | 0x40
|
||||
*/
|
||||
#define SD_CMD0 0 /*!< CMD0 = 0x40 */
|
||||
#define SD_CMD8 8 /*!< CMD8 = 0x48 */
|
||||
#define SD_CMD9 9 /*!< CMD9 = 0x49 */
|
||||
#define SD_CMD10 10 /*!< CMD10 = 0x4A */
|
||||
#define SD_CMD12 12 /*!< CMD12 = 0x4C */
|
||||
#define SD_CMD16 16 /*!< CMD16 = 0x50 */
|
||||
#define SD_CMD17 17 /*!< CMD17 = 0x51 */
|
||||
#define SD_CMD18 18 /*!< CMD18 = 0x52 */
|
||||
#define SD_ACMD23 23 /*!< CMD23 = 0x57 */
|
||||
#define SD_CMD24 24 /*!< CMD24 = 0x58 */
|
||||
#define SD_CMD25 25 /*!< CMD25 = 0x59 */
|
||||
#define SD_ACMD41 41 /*!< ACMD41 = 0x41 */
|
||||
#define SD_CMD55 55 /*!< CMD55 = 0x55 */
|
||||
#define SD_CMD58 58 /*!< CMD58 = 0x58 */
|
||||
#define SD_CMD59 59 /*!< CMD59 = 0x59 */
|
||||
|
||||
SD_CardInfo cardinfo;
|
||||
|
||||
void sdcard_init() {
|
||||
uint8 cardinfo = sd_init();
|
||||
if(cardinfo) {
|
||||
panic("sd card init error\n");
|
||||
} else
|
||||
{
|
||||
printf("sdcard init: %d\n", cardinfo);
|
||||
}
|
||||
}
|
||||
void SD_CS_HIGH(void)
|
||||
{
|
||||
gpiohs_set_pin(7, GPIO_PV_HIGH);
|
||||
}
|
||||
|
||||
void SD_CS_LOW(void)
|
||||
{
|
||||
gpiohs_set_pin(7, GPIO_PV_LOW);
|
||||
}
|
||||
|
||||
void SD_HIGH_SPEED_ENABLE(void)
|
||||
{
|
||||
// spi_set_clk_rate(SPI_DEVICE_0, 10000000);
|
||||
}
|
||||
|
||||
static void sd_lowlevel_init(uint8 spi_index)
|
||||
{
|
||||
gpiohs_set_drive_mode(7, GPIO_DM_OUTPUT);
|
||||
// spi_set_clk_rate(SPI_DEVICE_0, 200000); /*set clk rate*/
|
||||
}
|
||||
|
||||
static void sd_write_data(uint8 *data_buff, uint32 length)
|
||||
{
|
||||
spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
|
||||
spi_send_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
|
||||
}
|
||||
|
||||
static void sd_read_data(uint8 *data_buff, uint32 length)
|
||||
{
|
||||
|
||||
spi_init(SPI_DEVICE_0, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
|
||||
spi_receive_data_standard(SPI_DEVICE_0, SPI_CHIP_SELECT_3, NULL, 0, data_buff, length);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Send 5 bytes command to the SD card.
|
||||
* @param Cmd: The user expected command to send to SD card.
|
||||
* @param Arg: The command argument.
|
||||
* @param Crc: The CRC.
|
||||
* @retval None
|
||||
*/
|
||||
static void sd_send_cmd(uint8 cmd, uint32 arg, uint8 crc)
|
||||
{
|
||||
uint8 frame[6];
|
||||
/*!< Construct byte 1 */
|
||||
frame[0] = (cmd | 0x40);
|
||||
/*!< Construct byte 2 */
|
||||
frame[1] = (uint8)(arg >> 24);
|
||||
/*!< Construct byte 3 */
|
||||
frame[2] = (uint8)(arg >> 16);
|
||||
/*!< Construct byte 4 */
|
||||
frame[3] = (uint8)(arg >> 8);
|
||||
/*!< Construct byte 5 */
|
||||
frame[4] = (uint8)(arg);
|
||||
/*!< Construct CRC: byte 6 */
|
||||
frame[5] = (crc);
|
||||
/*!< SD chip select low */
|
||||
SD_CS_LOW();
|
||||
/*!< Send the Cmd bytes */
|
||||
sd_write_data(frame, 6);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Send 5 bytes command to the SD card.
|
||||
* @param Cmd: The user expected command to send to SD card.
|
||||
* @param Arg: The command argument.
|
||||
* @param Crc: The CRC.
|
||||
* @retval None
|
||||
*/
|
||||
static void sd_end_cmd(void)
|
||||
{
|
||||
uint8 frame[1] = {0xFF};
|
||||
/*!< SD chip select high */
|
||||
SD_CS_HIGH();
|
||||
/*!< Send the Cmd bytes */
|
||||
sd_write_data(frame, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Returns the SD response.
|
||||
* @param None
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
static uint8 sd_get_response(void)
|
||||
{
|
||||
uint8 result;
|
||||
uint16 timeout = 0x0FFF;
|
||||
/*!< Check if response is got or a timeout is happen */
|
||||
while (timeout--) {
|
||||
sd_read_data(&result, 1);
|
||||
// sd_read_data_dma(&result);
|
||||
/*!< Right response got */
|
||||
if (result != 0xFF)
|
||||
return result;
|
||||
}
|
||||
/*!< After time out */
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Get SD card data response.
|
||||
* @param None
|
||||
* @retval The SD status: Read data response xxx0<status>1
|
||||
* - status 010: Data accecpted
|
||||
* - status 101: Data rejected due to a crc error
|
||||
* - status 110: Data rejected due to a Write error.
|
||||
* - status 111: Data rejected due to other error.
|
||||
*/
|
||||
static uint8 sd_get_dataresponse(void)
|
||||
{
|
||||
uint8 response;
|
||||
/*!< Read resonse */
|
||||
sd_read_data(&response, 1);
|
||||
/*!< Mask unused bits */
|
||||
response &= 0x1F;
|
||||
if (response != 0x05)
|
||||
return 0xFF;
|
||||
/*!< Wait null data */
|
||||
sd_read_data(&response, 1);
|
||||
while (response == 0)
|
||||
sd_read_data(&response, 1);
|
||||
/*!< Return response */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Read the CSD card register
|
||||
* Reading the contents of the CSD register in SPI mode is a simple
|
||||
* read-block transaction.
|
||||
* @param SD_csd: pointer on an SCD register structure
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
static uint8 sd_get_csdregister(SD_CSD *SD_csd)
|
||||
{
|
||||
uint8 csd_tab[18];
|
||||
/*!< Send CMD9 (CSD register) or CMD10(CSD register) */
|
||||
sd_send_cmd(SD_CMD9, 0, 0);
|
||||
/*!< Wait for response in the R1 format (0x00 is no errors) */
|
||||
if (sd_get_response() != 0x00) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
/*!< Store CSD register value on csd_tab */
|
||||
/*!< Get CRC bytes (not really needed by us, but required by SD) */
|
||||
sd_read_data(csd_tab, 18);
|
||||
sd_end_cmd();
|
||||
/*!< Byte 0 */
|
||||
SD_csd->CSDStruct = (csd_tab[0] & 0xC0) >> 6;
|
||||
SD_csd->SysSpecVersion = (csd_tab[0] & 0x3C) >> 2;
|
||||
SD_csd->Reserved1 = csd_tab[0] & 0x03;
|
||||
/*!< Byte 1 */
|
||||
SD_csd->TAAC = csd_tab[1];
|
||||
/*!< Byte 2 */
|
||||
SD_csd->NSAC = csd_tab[2];
|
||||
/*!< Byte 3 */
|
||||
SD_csd->MaxBusClkFrec = csd_tab[3];
|
||||
/*!< Byte 4 */
|
||||
SD_csd->CardComdClasses = csd_tab[4] << 4;
|
||||
/*!< Byte 5 */
|
||||
SD_csd->CardComdClasses |= (csd_tab[5] & 0xF0) >> 4;
|
||||
SD_csd->RdBlockLen = csd_tab[5] & 0x0F;
|
||||
/*!< Byte 6 */
|
||||
SD_csd->PartBlockRead = (csd_tab[6] & 0x80) >> 7;
|
||||
SD_csd->WrBlockMisalign = (csd_tab[6] & 0x40) >> 6;
|
||||
SD_csd->RdBlockMisalign = (csd_tab[6] & 0x20) >> 5;
|
||||
SD_csd->DSRImpl = (csd_tab[6] & 0x10) >> 4;
|
||||
SD_csd->Reserved2 = 0; /*!< Reserved */
|
||||
SD_csd->DeviceSize = (csd_tab[6] & 0x03) << 10;
|
||||
/*!< Byte 7 */
|
||||
SD_csd->DeviceSize = (csd_tab[7] & 0x3F) << 16;
|
||||
/*!< Byte 8 */
|
||||
SD_csd->DeviceSize |= csd_tab[8] << 8;
|
||||
/*!< Byte 9 */
|
||||
SD_csd->DeviceSize |= csd_tab[9];
|
||||
/*!< Byte 10 */
|
||||
SD_csd->EraseGrSize = (csd_tab[10] & 0x40) >> 6;
|
||||
SD_csd->EraseGrMul = (csd_tab[10] & 0x3F) << 1;
|
||||
/*!< Byte 11 */
|
||||
SD_csd->EraseGrMul |= (csd_tab[11] & 0x80) >> 7;
|
||||
SD_csd->WrProtectGrSize = (csd_tab[11] & 0x7F);
|
||||
/*!< Byte 12 */
|
||||
SD_csd->WrProtectGrEnable = (csd_tab[12] & 0x80) >> 7;
|
||||
SD_csd->ManDeflECC = (csd_tab[12] & 0x60) >> 5;
|
||||
SD_csd->WrSpeedFact = (csd_tab[12] & 0x1C) >> 2;
|
||||
SD_csd->MaxWrBlockLen = (csd_tab[12] & 0x03) << 2;
|
||||
/*!< Byte 13 */
|
||||
SD_csd->MaxWrBlockLen |= (csd_tab[13] & 0xC0) >> 6;
|
||||
SD_csd->WriteBlockPaPartial = (csd_tab[13] & 0x20) >> 5;
|
||||
SD_csd->Reserved3 = 0;
|
||||
SD_csd->ContentProtectAppli = (csd_tab[13] & 0x01);
|
||||
/*!< Byte 14 */
|
||||
SD_csd->FileFormatGrouop = (csd_tab[14] & 0x80) >> 7;
|
||||
SD_csd->CopyFlag = (csd_tab[14] & 0x40) >> 6;
|
||||
SD_csd->PermWrProtect = (csd_tab[14] & 0x20) >> 5;
|
||||
SD_csd->TempWrProtect = (csd_tab[14] & 0x10) >> 4;
|
||||
SD_csd->FileFormat = (csd_tab[14] & 0x0C) >> 2;
|
||||
SD_csd->ECC = (csd_tab[14] & 0x03);
|
||||
/*!< Byte 15 */
|
||||
SD_csd->CSD_CRC = (csd_tab[15] & 0xFE) >> 1;
|
||||
SD_csd->Reserved4 = 1;
|
||||
/*!< Return the reponse */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Read the CID card register.
|
||||
* Reading the contents of the CID register in SPI mode is a simple
|
||||
* read-block transaction.
|
||||
* @param SD_cid: pointer on an CID register structure
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
static uint8 sd_get_cidregister(SD_CID *SD_cid)
|
||||
{
|
||||
uint8 cid_tab[18];
|
||||
/*!< Send CMD10 (CID register) */
|
||||
sd_send_cmd(SD_CMD10, 0, 0);
|
||||
/*!< Wait for response in the R1 format (0x00 is no errors) */
|
||||
if (sd_get_response() != 0x00) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
/*!< Store CID register value on cid_tab */
|
||||
/*!< Get CRC bytes (not really needed by us, but required by SD) */
|
||||
sd_read_data(cid_tab, 18);
|
||||
sd_end_cmd();
|
||||
/*!< Byte 0 */
|
||||
SD_cid->ManufacturerID = cid_tab[0];
|
||||
/*!< Byte 1 */
|
||||
SD_cid->OEM_AppliID = cid_tab[1] << 8;
|
||||
/*!< Byte 2 */
|
||||
SD_cid->OEM_AppliID |= cid_tab[2];
|
||||
/*!< Byte 3 */
|
||||
SD_cid->ProdName1 = cid_tab[3] << 24;
|
||||
/*!< Byte 4 */
|
||||
SD_cid->ProdName1 |= cid_tab[4] << 16;
|
||||
/*!< Byte 5 */
|
||||
SD_cid->ProdName1 |= cid_tab[5] << 8;
|
||||
/*!< Byte 6 */
|
||||
SD_cid->ProdName1 |= cid_tab[6];
|
||||
/*!< Byte 7 */
|
||||
SD_cid->ProdName2 = cid_tab[7];
|
||||
/*!< Byte 8 */
|
||||
SD_cid->ProdRev = cid_tab[8];
|
||||
/*!< Byte 9 */
|
||||
SD_cid->ProdSN = cid_tab[9] << 24;
|
||||
/*!< Byte 10 */
|
||||
SD_cid->ProdSN |= cid_tab[10] << 16;
|
||||
/*!< Byte 11 */
|
||||
SD_cid->ProdSN |= cid_tab[11] << 8;
|
||||
/*!< Byte 12 */
|
||||
SD_cid->ProdSN |= cid_tab[12];
|
||||
/*!< Byte 13 */
|
||||
SD_cid->Reserved1 |= (cid_tab[13] & 0xF0) >> 4;
|
||||
SD_cid->ManufactDate = (cid_tab[13] & 0x0F) << 8;
|
||||
/*!< Byte 14 */
|
||||
SD_cid->ManufactDate |= cid_tab[14];
|
||||
/*!< Byte 15 */
|
||||
SD_cid->CID_CRC = (cid_tab[15] & 0xFE) >> 1;
|
||||
SD_cid->Reserved2 = 1;
|
||||
/*!< Return the reponse */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Returns information about specific card.
|
||||
* @param cardinfo: pointer to a SD_CardInfo structure that contains all SD
|
||||
* card information.
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
static uint8 sd_get_cardinfo(SD_CardInfo *cardinfo)
|
||||
{
|
||||
if (sd_get_csdregister(&(cardinfo->SD_csd)))
|
||||
return 0xFF;
|
||||
if (sd_get_cidregister(&(cardinfo->SD_cid)))
|
||||
return 0xFF;
|
||||
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 1024;
|
||||
cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);
|
||||
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
|
||||
/*!< Returns the reponse */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Initializes the SD/SD communication.
|
||||
* @param None
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
uint8 sd_init(void)
|
||||
{
|
||||
uint8 frame[10], index, result;
|
||||
/*!< Initialize SD_SPI */
|
||||
sd_lowlevel_init(0);
|
||||
/*!< SD chip select high */
|
||||
SD_CS_HIGH();
|
||||
/*!< Send dummy byte 0xFF, 10 times with CS high */
|
||||
/*!< Rise CS and MOSI for 80 clocks cycles */
|
||||
/*!< Send dummy byte 0xFF */
|
||||
for (index = 0; index < 10; index++)
|
||||
frame[index] = 0xFF;
|
||||
sd_write_data(frame, 10);
|
||||
/*------------Put SD in SPI mode--------------*/
|
||||
/*!< SD initialized and set to SPI mode properly */
|
||||
|
||||
index = 0xFF;
|
||||
while (index--) {
|
||||
sd_send_cmd(SD_CMD0, 0, 0x95);
|
||||
// printf("get_response: %d\n", index);
|
||||
result = sd_get_response();
|
||||
sd_end_cmd();
|
||||
if (result == 0x01)
|
||||
break;
|
||||
}
|
||||
if (index == 0)
|
||||
{
|
||||
printf("SD_CMD0 is %X\n", result);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
sd_send_cmd(SD_CMD8, 0x01AA, 0x87);
|
||||
/*!< 0x01 or 0x05 */
|
||||
result = sd_get_response();
|
||||
sd_read_data(frame, 4);
|
||||
sd_end_cmd();
|
||||
if (result != 0x01)
|
||||
{
|
||||
printf("SD_CMD8 is %X\n", result);
|
||||
return 0xFF;
|
||||
}
|
||||
index = 0xFF;
|
||||
while (index--) {
|
||||
sd_send_cmd(SD_CMD55, 0, 0);
|
||||
result = sd_get_response();
|
||||
sd_end_cmd();
|
||||
if (result != 0x01)
|
||||
return 0xFF;
|
||||
sd_send_cmd(SD_ACMD41, 0x40000000, 0);
|
||||
result = sd_get_response();
|
||||
sd_end_cmd();
|
||||
if (result == 0x00)
|
||||
break;
|
||||
}
|
||||
if (index == 0)
|
||||
{
|
||||
printf("SD_CMD55 is %X\n", result);
|
||||
return 0xFF;
|
||||
}
|
||||
index = 255;
|
||||
while(index--){
|
||||
sd_send_cmd(SD_CMD58, 0, 1);
|
||||
result = sd_get_response();
|
||||
sd_read_data(frame, 4);
|
||||
sd_end_cmd();
|
||||
if(result == 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(index == 0)
|
||||
{
|
||||
printf("SD_CMD58 is %X\n", result);
|
||||
return 0xFF;
|
||||
}
|
||||
if ((frame[0] & 0x40) == 0)
|
||||
return 0xFF;
|
||||
SD_HIGH_SPEED_ENABLE();
|
||||
return sd_get_cardinfo(&cardinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Reads a block of data from the SD.
|
||||
* @param data_buff: pointer to the buffer that receives the data read from the
|
||||
* SD.
|
||||
* @param sector: SD's internal address to read from.
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
uint8 sd_read_sector(uint8 *data_buff, uint32 sector, uint32 count)
|
||||
{
|
||||
uint8 frame[2], flag;
|
||||
/*!< Send CMD17 (SD_CMD17) to read one block */
|
||||
if (count == 1) {
|
||||
flag = 0;
|
||||
sd_send_cmd(SD_CMD17, sector, 0);
|
||||
} else {
|
||||
flag = 1;
|
||||
sd_send_cmd(SD_CMD18, sector, 0);
|
||||
}
|
||||
/*!< Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
|
||||
if (sd_get_response() != 0x00) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
while (count) {
|
||||
if (sd_get_response() != SD_START_DATA_SINGLE_BLOCK_READ)
|
||||
break;
|
||||
/*!< Read the SD block data : read NumByteToRead data */
|
||||
sd_read_data(data_buff, 512);
|
||||
/*!< Get CRC bytes (not really needed by us, but required by SD) */
|
||||
sd_read_data(frame, 2);
|
||||
data_buff += 512;
|
||||
count--;
|
||||
}
|
||||
sd_end_cmd();
|
||||
if (flag) {
|
||||
sd_send_cmd(SD_CMD12, 0, 0);
|
||||
sd_get_response();
|
||||
sd_end_cmd();
|
||||
sd_end_cmd();
|
||||
}
|
||||
/*!< Returns the reponse */
|
||||
return count > 0 ? 0xFF : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Writes a block on the SD
|
||||
* @param data_buff: pointer to the buffer containing the data to be written on
|
||||
* the SD.
|
||||
* @param sector: address to write on.
|
||||
* @retval The SD Response:
|
||||
* - 0xFF: Sequence failed
|
||||
* - 0: Sequence succeed
|
||||
*/
|
||||
uint8 sd_write_sector(uint8 *data_buff, uint32 sector, uint32 count)
|
||||
{
|
||||
uint8 frame[2] = {0xFF};
|
||||
|
||||
if (count == 1) {
|
||||
frame[1] = SD_START_DATA_SINGLE_BLOCK_WRITE;
|
||||
sd_send_cmd(SD_CMD24, sector, 0);
|
||||
} else {
|
||||
frame[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE;
|
||||
sd_send_cmd(SD_ACMD23, count, 0);
|
||||
sd_get_response();
|
||||
sd_end_cmd();
|
||||
sd_send_cmd(SD_CMD25, sector, 0);
|
||||
}
|
||||
/*!< Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */
|
||||
if (sd_get_response() != 0x00) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
while (count--) {
|
||||
/*!< Send the data token to signify the start of the data */
|
||||
sd_write_data(frame, 2);
|
||||
/*!< Write the block data to SD : write count data by block */
|
||||
sd_write_data(data_buff, 512);
|
||||
/*!< Put CRC bytes (not really needed by us, but required by SD) */
|
||||
sd_write_data(frame, 2);
|
||||
data_buff += 512;
|
||||
/*!< Read data response */
|
||||
if (sd_get_dataresponse() != 0x00) {
|
||||
sd_end_cmd();
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
sd_end_cmd();
|
||||
sd_end_cmd();
|
||||
/*!< Returns the reponse */
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,582 @@
|
|||
//
|
||||
// Created by lumin on 2020/11/2.
|
||||
//
|
||||
#include <sdcard.h>
|
||||
#include <fpioa.h>
|
||||
#include <gpiohs.h>
|
||||
#include <spi.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SECTOR_SIZE (512)
|
||||
|
||||
#define SD_SPI_CLK (200000UL)
|
||||
#define SD_SPI_HIGH_SPEED_CLK (25000000UL)
|
||||
#define SD_SPI_DEVICE SPI_DEVICE_1
|
||||
#define SD_SPI_WORK_MODE SPI_WORK_MODE_0
|
||||
#define SD_SPI_FRAME_FORMAT SPI_FF_STANDARD
|
||||
#define SD_SPI_DATA_BIT_LENGTH 8
|
||||
#define SD_SPI_ENDIAN 0
|
||||
#define SD_SPI_CHIP_SELECT SPI_CHIP_SELECT_1
|
||||
|
||||
#define SD_CMD0_ARGS (0)
|
||||
#define SD_CMD0_CRC (0x95)
|
||||
#define SD_CMD55_ARGS (0)
|
||||
#define SD_CMD55_CRC (0)
|
||||
#define SD_ACMD41_CRC (0)
|
||||
#define SD_CMD58_ARGS (0)
|
||||
#define SD_CMD58_CRC (1)
|
||||
#define SD_CMD10_ARGS (0)
|
||||
#define SD_CMD10_CRC (0)
|
||||
#define SD_VOLTAGE_SELECT (0x0100)
|
||||
#define SD_CHECK_PATTERN (0xAA)
|
||||
#define SD_CMD8_CRC (0x87)
|
||||
#define SD_HIGH_CAPACITY (0x40000000)
|
||||
#define SD_ERROR_RES (0xFF)
|
||||
#define SD_TIMEMOUT_COUNT (0xFF)
|
||||
|
||||
static void sdcard_pin_mapping_init();
|
||||
static void sdcard_gpiohs_init();
|
||||
static void sdcard_spi_init();
|
||||
static void sd_SPI_mode_prepare();
|
||||
static void SD_CS_HIGH();
|
||||
static void SD_CS_LOW();
|
||||
static void SD_HIGH_SPEED_ENABLE();
|
||||
static void sd_write_data(uint8_t *frame, uint32_t length);
|
||||
static void sd_read_data(uint8_t *frame, uint32_t length);
|
||||
static void sd_send_cmd(uint8_t cmd, uint32_t args, uint8_t crc);
|
||||
static void sd_end_cmd();
|
||||
static uint8_t sd_get_R1_response();
|
||||
static void sd_get_R3_rest_response(uint8_t *frame);
|
||||
static void sd_get_R7_rest_response(uint8_t *frame);
|
||||
static uint8_t sd_get_data_write_response();
|
||||
static int sd_switch_to_SPI_mode();
|
||||
static int sd_negotiate_voltage();
|
||||
static int sd_set_SDXC_capacity();
|
||||
static int sd_query_capacity_status();
|
||||
static int sd_get_cardinfo(SD_CardInfo *cardinfo);
|
||||
static int sd_get_csdregister(SD_CSD *SD_csd);
|
||||
static int sd_get_cidregister(SD_CID *SD_cid);
|
||||
static void sd_test();
|
||||
|
||||
sdcard_hardware_pin_config_t config = {
|
||||
28, 26, 27, 29, 29
|
||||
};
|
||||
|
||||
SD_CardInfo cardinfo;
|
||||
|
||||
void sd_init()
|
||||
{
|
||||
cardinfo.active = 0;
|
||||
|
||||
// Part 1: Hardware infrastructure configuration
|
||||
sdcard_pin_mapping_init();
|
||||
sdcard_gpiohs_init();
|
||||
sdcard_spi_init();
|
||||
|
||||
// Part 2: SD protocol(SPI Mode)
|
||||
sd_SPI_mode_prepare();
|
||||
|
||||
if(sd_switch_to_SPI_mode() != 0)
|
||||
return;
|
||||
if(sd_negotiate_voltage() != 0)
|
||||
return;
|
||||
if(sd_set_SDXC_capacity() != 0)
|
||||
return;
|
||||
if(sd_query_capacity_status() != 0)
|
||||
return;
|
||||
|
||||
SD_HIGH_SPEED_ENABLE();
|
||||
|
||||
if(sd_get_cardinfo(&cardinfo) != 0)
|
||||
return;
|
||||
|
||||
// Part 3: Read/Write test
|
||||
// sd_test();
|
||||
cprintf("Successfully initialize SD card!\n");
|
||||
}
|
||||
|
||||
uint8_t sd_read_sector(uint8_t *data_buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
uint8_t dummy_crc[2], multiple;
|
||||
if (count == 1){
|
||||
multiple = 0;
|
||||
sd_send_cmd(SD_CMD17, sector, 0);
|
||||
} else{
|
||||
multiple = 1;
|
||||
sd_send_cmd(SD_CMD18, sector, 0);
|
||||
}
|
||||
|
||||
uint32_t result = sd_get_R1_response();
|
||||
if (result != SD_TRANS_MODE_RESULT_OK) {
|
||||
cprintf("Read sector(s) CMD error! result = %d\n", result);
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
while (count)
|
||||
{
|
||||
result = sd_get_R1_response();
|
||||
if (result != SD_START_DATA_READ_RESPONSE) {
|
||||
cprintf("Data read response error! result = %d\n", result);
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
sd_read_data(data_buff, SECTOR_SIZE);
|
||||
sd_read_data(dummy_crc, 2);
|
||||
|
||||
data_buff += SECTOR_SIZE;
|
||||
count--;
|
||||
}
|
||||
|
||||
sd_end_cmd();
|
||||
if (multiple){
|
||||
sd_send_cmd(SD_CMD12, 0, 0);
|
||||
sd_get_R1_response();
|
||||
sd_end_cmd();
|
||||
sd_end_cmd();
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
cprintf("Not all sectors are read!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t sd_write_sector(uint8_t *data_buff, uint32_t sector, uint32_t count)
|
||||
{
|
||||
assert(((uint32_t)data_buff) % 4 == 0);
|
||||
uint8_t token[2] = {0xFF, 0x00}, dummpy_crc[2] = {0xFF, 0xFF};
|
||||
|
||||
if (count == 1){
|
||||
token[1] = SD_START_DATA_SINGLE_BLOCK_WRITE_TOKEN;
|
||||
sd_send_cmd(SD_CMD24, sector, 0);
|
||||
} else{
|
||||
token[1] = SD_START_DATA_MULTIPLE_BLOCK_WRITE_TOKEN;
|
||||
sd_send_cmd(SD_ACMD23, count, 0);
|
||||
sd_get_R1_response();
|
||||
sd_end_cmd();
|
||||
sd_send_cmd(SD_CMD25, sector, 0);
|
||||
}
|
||||
|
||||
if (sd_get_R1_response() != SD_TRANS_MODE_RESULT_OK) {
|
||||
cprintf("Write sector(s) CMD error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
while (count)
|
||||
{
|
||||
sd_write_data(token, 2);
|
||||
sd_write_data(data_buff, SECTOR_SIZE);
|
||||
sd_write_data(dummpy_crc, 2);
|
||||
|
||||
if (sd_get_data_write_response() != SD_TRANS_MODE_RESULT_OK) {
|
||||
cprintf("Data write response error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
data_buff += SECTOR_SIZE;
|
||||
count--;
|
||||
}
|
||||
|
||||
sd_end_cmd();
|
||||
sd_end_cmd();
|
||||
|
||||
if (count > 0) {
|
||||
cprintf("Not all sectors are written!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdcard_pin_mapping_init()
|
||||
{
|
||||
fpioa_set_function(config.sclk_pin, FUNC_SPI1_SCLK);
|
||||
fpioa_set_function(config.mosi_pin, FUNC_SPI1_D0);
|
||||
fpioa_set_function(config.miso_pin, FUNC_SPI1_D1);
|
||||
fpioa_set_function(config.cs_pin, FUNC_GPIOHS0 + config.cs_gpio_num);
|
||||
}
|
||||
|
||||
static void sdcard_gpiohs_init()
|
||||
{
|
||||
gpiohs_set_drive_mode(config.cs_gpio_num, GPIO_DM_OUTPUT);
|
||||
}
|
||||
|
||||
static void sdcard_spi_init()
|
||||
{
|
||||
spi_set_clk_rate(SD_SPI_DEVICE, SD_SPI_CLK);
|
||||
}
|
||||
|
||||
static void sd_SPI_mode_prepare()
|
||||
{
|
||||
/*!< Send dummy byte 0xFF, 10 times with CS high */
|
||||
/*!< Rise CS and MOSI for 80 clocks cycles */
|
||||
/*!< Send dummy byte 0xFF */
|
||||
uint8_t frame[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
frame[i] = SD_EMPTY_FILL;
|
||||
/*!< SD chip select high */
|
||||
SD_CS_HIGH();
|
||||
sd_write_data(frame, 10);
|
||||
}
|
||||
|
||||
static void SD_CS_HIGH()
|
||||
{
|
||||
gpiohs_set_pin_output_value(config.cs_gpio_num, GPIO_PV_HIGH);
|
||||
}
|
||||
|
||||
static void SD_CS_LOW()
|
||||
{
|
||||
gpiohs_set_pin_output_value(config.cs_gpio_num, GPIO_PV_LOW);
|
||||
}
|
||||
|
||||
static void SD_HIGH_SPEED_ENABLE()
|
||||
{
|
||||
spi_set_clk_rate(SD_SPI_DEVICE, SD_SPI_HIGH_SPEED_CLK);
|
||||
}
|
||||
|
||||
static void sd_write_data(uint8_t *frame, uint32_t length)
|
||||
{
|
||||
spi_init(SD_SPI_DEVICE, SD_SPI_WORK_MODE,
|
||||
SD_SPI_FRAME_FORMAT, SD_SPI_DATA_BIT_LENGTH, SD_SPI_ENDIAN);
|
||||
spi_send_data_standard(SD_SPI_DEVICE, SD_SPI_CHIP_SELECT, frame, length);
|
||||
}
|
||||
|
||||
static void sd_read_data(uint8_t *frame, uint32_t length)
|
||||
{
|
||||
spi_init(SD_SPI_DEVICE, SD_SPI_WORK_MODE,
|
||||
SD_SPI_FRAME_FORMAT, SD_SPI_DATA_BIT_LENGTH, SD_SPI_ENDIAN);
|
||||
spi_receive_data_standard(SD_SPI_DEVICE, SD_SPI_CHIP_SELECT, frame, length);
|
||||
}
|
||||
|
||||
static void sd_send_cmd(uint8_t cmd, uint32_t args, uint8_t crc)
|
||||
{
|
||||
// prepare cmd frame
|
||||
uint8_t frame[SD_CMD_FRAME_SIZE];
|
||||
frame[SD_CMD_CMD_BIT] = (SD_CMD_SIGN | cmd);
|
||||
frame[SD_CMD_ARG_MSB0] = (uint8_t)(args >> 24);
|
||||
frame[SD_CMD_ARG_MSB1] = (uint8_t)(args >> 16);
|
||||
frame[SD_CMD_ARG_MSB2] = (uint8_t)(args >> 8);
|
||||
frame[SD_CMD_ARG_MSB3] = (uint8_t)args;
|
||||
frame[SD_CMD_CRC_BIT] = crc;
|
||||
|
||||
// real send operation
|
||||
SD_CS_LOW();
|
||||
sd_write_data(frame,SD_CMD_FRAME_SIZE);
|
||||
}
|
||||
|
||||
static void sd_end_cmd()
|
||||
{
|
||||
uint8_t fill = SD_EMPTY_FILL;
|
||||
SD_CS_HIGH();
|
||||
sd_write_data(&fill, 1);
|
||||
}
|
||||
|
||||
static uint8_t sd_get_R1_response()
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
uint16_t timeout = SD_TIMEMOUT_COUNT;
|
||||
while (timeout--)
|
||||
{
|
||||
sd_read_data(&result, 1);
|
||||
if (result != SD_EMPTY_FILL)
|
||||
return result;
|
||||
}
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
static void sd_get_R3_rest_response(uint8_t *frame)
|
||||
{
|
||||
sd_read_data(frame, SD_R3_RESPONSE_REST_LENGTH);
|
||||
}
|
||||
|
||||
static void sd_get_R7_rest_response(uint8_t *frame)
|
||||
{
|
||||
sd_read_data(frame, SD_R7_RESPONSE_REST_LENGTH);
|
||||
}
|
||||
|
||||
static uint8_t sd_get_data_write_response()
|
||||
{
|
||||
uint8_t result;
|
||||
sd_read_data(&result, 1);
|
||||
|
||||
// protocol defined correct response
|
||||
if ((result & 0x1F) != 0x05)
|
||||
return SD_ERROR_RES;
|
||||
|
||||
do {
|
||||
sd_read_data(&result, 1);
|
||||
} while (result == SD_TRANS_MODE_RESULT_OK);
|
||||
|
||||
return SD_TRANS_MODE_RESULT_OK;
|
||||
}
|
||||
|
||||
static int sd_switch_to_SPI_mode()
|
||||
{
|
||||
uint8_t result;
|
||||
sd_send_cmd(SD_CMD0, SD_CMD0_ARGS, SD_CMD0_CRC);
|
||||
result = sd_get_R1_response();
|
||||
sd_end_cmd();
|
||||
|
||||
if (result != SD_INIT_MODE_RESULT_OK){
|
||||
cprintf("Fail to connect to SD card!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_negotiate_voltage()
|
||||
{
|
||||
uint8_t frame[SD_R7_RESPONSE_REST_LENGTH],result;
|
||||
sd_send_cmd(SD_CMD8, SD_VOLTAGE_SELECT | SD_CHECK_PATTERN, SD_CMD8_CRC);
|
||||
result = sd_get_R1_response();
|
||||
sd_get_R7_rest_response(frame);
|
||||
sd_end_cmd();
|
||||
|
||||
if (result != SD_INIT_MODE_RESULT_OK){
|
||||
cprintf("Fail to negotiate voltage with SD card!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_set_SDXC_capacity()
|
||||
{
|
||||
uint8_t result;
|
||||
|
||||
uint16_t timeout = SD_TIMEMOUT_COUNT;
|
||||
while (timeout--)
|
||||
{
|
||||
sd_send_cmd(SD_CMD55, SD_CMD55_ARGS, SD_CMD55_CRC);
|
||||
result = sd_get_R1_response();
|
||||
sd_end_cmd();
|
||||
if (result != SD_INIT_MODE_RESULT_OK){
|
||||
cprintf("Fail to prepare application command when set SDXC capacity!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
sd_send_cmd(SD_ACMD41, SD_HIGH_CAPACITY, SD_ACMD41_CRC);
|
||||
result = sd_get_R1_response();
|
||||
sd_end_cmd();
|
||||
if (result == SD_TRANS_MODE_RESULT_OK)
|
||||
return 0;
|
||||
}
|
||||
cprintf("Timeout to set card capacity!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
static int sd_query_capacity_status()
|
||||
{
|
||||
uint8_t frame[SD_R3_RESPONSE_REST_LENGTH], result;
|
||||
|
||||
uint16_t timeout = SD_TIMEMOUT_COUNT;
|
||||
while (timeout--)
|
||||
{
|
||||
sd_send_cmd(SD_CMD58, SD_CMD58_ARGS, SD_CMD58_CRC);
|
||||
result = sd_get_R1_response();
|
||||
sd_get_R3_rest_response(frame);
|
||||
sd_end_cmd();
|
||||
if (result == SD_TRANS_MODE_RESULT_OK)
|
||||
break;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
cprintf("Timeout to query card capacity status!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
// protocol defined correct response format
|
||||
if ((frame[0] & 0x40) == 0) {
|
||||
cprintf("SDXC card capacity status wrong!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_get_cardinfo(SD_CardInfo *cardinfo)
|
||||
{
|
||||
if(sd_get_csdregister(&cardinfo->SD_csd) != 0)
|
||||
return SD_ERROR_RES;
|
||||
if(sd_get_cidregister(&cardinfo->SD_cid) != 0)
|
||||
return SD_ERROR_RES;
|
||||
|
||||
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 2 * SECTOR_SIZE;
|
||||
cardinfo->CardBlockSize = (1 << (cardinfo->SD_csd.RdBlockLen));
|
||||
cardinfo->CardCapacity *= cardinfo->CardBlockSize;
|
||||
cardinfo->active = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_get_csdregister(SD_CSD *SD_csd)
|
||||
{
|
||||
uint8_t csd_frame[18];
|
||||
|
||||
// protocol
|
||||
sd_send_cmd(SD_CMD9, 0, 0);
|
||||
if (sd_get_R1_response() != SD_TRANS_MODE_RESULT_OK) {
|
||||
cprintf("Get CSD cmd error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
if (sd_get_R1_response() != SD_START_DATA_READ_RESPONSE) {
|
||||
cprintf("Get CSD data response error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
// retrieve data, 16 for SD_CID, 2 for CRC
|
||||
sd_read_data(csd_frame, 18);
|
||||
sd_end_cmd();
|
||||
|
||||
// set field
|
||||
SD_csd->CSDStruct = csd_frame[0] >> 6;
|
||||
SD_csd->SysSpecVersion = (csd_frame[0] & 0x3C) >> 2;
|
||||
SD_csd->Reserved1 = csd_frame[0] & 0x03;
|
||||
|
||||
SD_csd->TAAC = csd_frame[1];
|
||||
|
||||
SD_csd->NSAC = csd_frame[2];
|
||||
|
||||
SD_csd->MaxBusClkFrec = csd_frame[3];
|
||||
|
||||
SD_csd->CardComdClasses = (csd_frame[4] << 4);
|
||||
|
||||
SD_csd->CardComdClasses |= (csd_frame[5] >> 4);
|
||||
SD_csd->RdBlockLen = csd_frame[5] & 0x0F;
|
||||
|
||||
SD_csd->PartBlockRead = csd_frame[6] >> 7;
|
||||
SD_csd->WrBlockMisalign = (csd_frame[6] & 0x40) >> 6;
|
||||
SD_csd->RdBlockMisalign = (csd_frame[6] & 0x20) >> 5;
|
||||
SD_csd->DSRImpl = (csd_frame[6] & 0x10) >> 4;
|
||||
SD_csd->Reserved2 = 0;
|
||||
|
||||
SD_csd->DeviceSize = (csd_frame[7] & 0x3F) << 16;
|
||||
SD_csd->DeviceSize |= csd_frame[8] << 8;
|
||||
SD_csd->DeviceSize |= csd_frame[9];
|
||||
|
||||
SD_csd->EraseGrSize = (csd_frame[10] & 0x40) >> 6;
|
||||
SD_csd->EraseGrMul = ((csd_frame[10] & 0x3F) << 1);
|
||||
|
||||
SD_csd->EraseGrMul |= (csd_frame[11] >> 7);
|
||||
SD_csd->WrProtectGrSize = csd_frame[11] & 0x7F;
|
||||
|
||||
SD_csd->WrProtectGrEnable = csd_frame[12] >> 7;
|
||||
SD_csd->ManDeflECC = (csd_frame[12] & 0x60) >> 5;
|
||||
SD_csd->WrSpeedFact = (csd_frame[12] & 0x1C) >> 2;
|
||||
SD_csd->MaxWrBlockLen = ((csd_frame[12] & 0x03) << 2);
|
||||
|
||||
SD_csd->MaxWrBlockLen |= (csd_frame[13] >> 6);
|
||||
SD_csd->WriteBlockPaPartial = (csd_frame[13] & 0x20) >> 5;
|
||||
SD_csd->Reserved3 = 0;
|
||||
SD_csd->ContentProtectAppli = csd_frame[13] & 0x01;
|
||||
|
||||
SD_csd->FileFormatGrouop = csd_frame[14] >> 7;
|
||||
SD_csd->CopyFlag = (csd_frame[14] & 0x40) >> 6;
|
||||
SD_csd->PermWrProtect = (csd_frame[14] & 0x20) >> 5;
|
||||
SD_csd->TempWrProtect = (csd_frame[14] & 0x10) >> 4;
|
||||
SD_csd->FileFormat = (csd_frame[14] & 0x0C) >> 2;
|
||||
SD_csd->ECC = csd_frame[14] & 0x03;
|
||||
|
||||
SD_csd->CSD_CRC = csd_frame[15] >> 1;
|
||||
SD_csd->Reserved4 = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd_get_cidregister(SD_CID *SD_cid) {
|
||||
uint8_t cid_frame[18];
|
||||
|
||||
// protocol
|
||||
sd_send_cmd(SD_CMD10, SD_CMD10_ARGS, SD_CMD10_CRC);
|
||||
if (sd_get_R1_response() != SD_TRANS_MODE_RESULT_OK) {
|
||||
cprintf("Get CID cmd error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
if (sd_get_R1_response() != SD_START_DATA_READ_RESPONSE) {
|
||||
cprintf("Get CID data response error!\n");
|
||||
return SD_ERROR_RES;
|
||||
}
|
||||
|
||||
// retrieve data, 16 for SD_CID, 2 for CRC
|
||||
sd_read_data(cid_frame, 18);
|
||||
sd_end_cmd();
|
||||
|
||||
// set field
|
||||
SD_cid->ManufacturerID = cid_frame[0];
|
||||
SD_cid->OEM_AppliID = (cid_frame[1] << 8);
|
||||
SD_cid->OEM_AppliID |= cid_frame[2];
|
||||
SD_cid->ProdName1 = (cid_frame[3] << 24);
|
||||
SD_cid->ProdName1 |= (cid_frame[4] << 16);
|
||||
SD_cid->ProdName1 |= (cid_frame[5] << 8);
|
||||
SD_cid->ProdName1 |= cid_frame[6];
|
||||
SD_cid->ProdName2 = cid_frame[7];
|
||||
SD_cid->ProdRev = cid_frame[8];
|
||||
SD_cid->ProdSN = (cid_frame[9] << 24);
|
||||
SD_cid->ProdSN |= (cid_frame[10] << 16);
|
||||
SD_cid->ProdSN |= (cid_frame[11] << 8);
|
||||
SD_cid->ProdSN |= cid_frame[12];
|
||||
SD_cid->Reserved1 = cid_frame[13] >> 4;
|
||||
SD_cid->ManufactDate = ((cid_frame[13] & 0x0F) << 8);
|
||||
SD_cid->ManufactDate |= cid_frame[14];
|
||||
SD_cid->CID_CRC = cid_frame[15] >> 1;
|
||||
SD_cid->Reserved2 = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sd_test()
|
||||
{
|
||||
uint64_t num_sectors = cardinfo.CardCapacity / SECTOR_SIZE;
|
||||
uint32_t sector = num_sectors - 10;
|
||||
|
||||
uint8_t buffer0[2 * SECTOR_SIZE], buffer1[2 * SECTOR_SIZE], buffer2[2 * SECTOR_SIZE], buffer3[2 * SECTOR_SIZE];
|
||||
const char *msg = "Well! I've often seen a cat without a grin', thought Alice, 'but a grin without a cat! It's the most curious thing I ever saw in my life!'";
|
||||
|
||||
cprintf("Start SD card read/write test\n", sector);
|
||||
|
||||
memset(buffer0, 0, SECTOR_SIZE);
|
||||
memset(buffer1, 0, SECTOR_SIZE);
|
||||
memset(buffer2, 0, SECTOR_SIZE);
|
||||
memset(buffer3, 0, SECTOR_SIZE);
|
||||
cprintf("- single sector read/write test on sector 0x%x\n", sector);
|
||||
assert(sd_read_sector(buffer0, sector, 1) == 0);
|
||||
cprintf("\tread sector 0x%x successfully!\n", sector);
|
||||
|
||||
memcpy(buffer1, msg, strlen(msg) + 1 );
|
||||
assert(memcmp(buffer1, buffer2, SECTOR_SIZE) != 0);
|
||||
assert(sd_write_sector(buffer1, sector, 1) == 0);
|
||||
cprintf("\twrite sector 0x%x successfully!\n", sector);
|
||||
|
||||
assert(sd_read_sector(buffer2, sector, 1) == 0);
|
||||
assert(memcmp(buffer1, buffer2, SECTOR_SIZE) == 0);
|
||||
cprintf("\treread sector 0x%x successfully!\n", sector);
|
||||
|
||||
assert(sd_write_sector(buffer0, sector, 1) == 0);
|
||||
assert(sd_read_sector(buffer3, sector, 1) == 0);
|
||||
assert(memcmp(buffer0, buffer3, SECTOR_SIZE) == 0);
|
||||
cprintf("\trestore sector 0x%x successfully!\n", sector);
|
||||
|
||||
memset(buffer0, 0, 2 * SECTOR_SIZE);
|
||||
memset(buffer1, 0, 2 * SECTOR_SIZE);
|
||||
memset(buffer2, 0, 2 * SECTOR_SIZE);
|
||||
memset(buffer3, 0, 2 * SECTOR_SIZE);
|
||||
cprintf("- multiple sector read/write test on sector 0x%x\n", sector);
|
||||
assert(sd_read_sector(buffer0, sector, 2) == 0);
|
||||
cprintf("\tread sector 0x%x successfully!\n", sector);
|
||||
|
||||
memcpy(buffer1, msg, strlen(msg) + 1 );
|
||||
assert(memcmp(buffer1, buffer2, 2 * SECTOR_SIZE) != 0);
|
||||
assert(sd_write_sector(buffer1, sector, 2) == 0);
|
||||
cprintf("\twrite sector 0x%x successfully!\n", sector);
|
||||
|
||||
assert(sd_read_sector(buffer2, sector, 2) == 0);
|
||||
assert(memcmp(buffer1, buffer2, 2 * SECTOR_SIZE) == 0);
|
||||
cprintf("\treread sector 0x%x successfully!\n", sector);
|
||||
|
||||
assert(sd_write_sector(buffer0, sector, 2) == 0);
|
||||
assert(sd_read_sector(buffer3, sector, 2) == 0);
|
||||
assert(memcmp(buffer0, buffer3, 2 * SECTOR_SIZE) == 0);
|
||||
cprintf("\trestore sector 0x%x successfully!\n", sector);
|
||||
|
||||
cprintf("SD card initialized successfully!\n");
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
// SPI Protocol Implementation
|
||||
|
||||
#include "include/types.h"
|
||||
#include "include/spi.h"
|
||||
#include "include/platform.h"
|
||||
#include "include/riscv.h"
|
||||
#include "include/utils.h"
|
||||
#include "include/defs.h"
|
||||
|
||||
volatile spi_t *const spi[4] =
|
||||
{
|
||||
(volatile spi_t *)SPI0_BASE_ADDR,
|
||||
(volatile spi_t *)SPI1_BASE_ADDR,
|
||||
(volatile spi_t *)SPI_SLAVE_BASE_ADDR,
|
||||
(volatile spi_t *)SPI3_BASE_ADDR};
|
||||
|
||||
void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
|
||||
uint64 data_bit_length, uint32 endian)
|
||||
{
|
||||
// configASSERT(data_bit_length >= 4 && data_bit_length <= 32);
|
||||
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
// spi_clk_init(spi_num);
|
||||
|
||||
// uint8 dfs_offset, frf_offset, work_mode_offset;
|
||||
uint8 dfs_offset = 0;
|
||||
uint8 frf_offset = 0;
|
||||
uint8 work_mode_offset = 0;
|
||||
switch(spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
dfs_offset = 16;
|
||||
frf_offset = 21;
|
||||
work_mode_offset = 6;
|
||||
break;
|
||||
case 2:
|
||||
// configASSERT(!"Spi Bus 2 Not Support!");
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
dfs_offset = 0;
|
||||
frf_offset = 22;
|
||||
work_mode_offset = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(frame_format)
|
||||
{
|
||||
case SPI_FF_DUAL:
|
||||
// configASSERT(data_bit_length % 2 == 0);
|
||||
break;
|
||||
case SPI_FF_QUAD:
|
||||
// configASSERT(data_bit_length % 4 == 0);
|
||||
break;
|
||||
case SPI_FF_OCTAL:
|
||||
// configASSERT(data_bit_length % 8 == 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
volatile spi_t *spi_adapter = spi[spi_num];
|
||||
if(spi_adapter->baudr == 0)
|
||||
spi_adapter->baudr = 0x14;
|
||||
spi_adapter->imr = 0x00;
|
||||
spi_adapter->dmacr = 0x00;
|
||||
spi_adapter->dmatdlr = 0x10;
|
||||
spi_adapter->dmardlr = 0x00;
|
||||
spi_adapter->ser = 0x00;
|
||||
spi_adapter->ssienr = 0x00;
|
||||
spi_adapter->ctrlr0 = (work_mode << work_mode_offset) | (frame_format << frf_offset) | ((data_bit_length - 1) << dfs_offset);
|
||||
spi_adapter->spi_ctrlr0 = 0;
|
||||
spi_adapter->endian = endian;
|
||||
}
|
||||
|
||||
|
||||
static void spi_set_tmod(uint8 spi_num, uint32 tmod)
|
||||
{
|
||||
// configASSERT(spi_num < SPI_DEVICE_MAX);
|
||||
volatile spi_t *spi_handle = spi[spi_num];
|
||||
uint8 tmod_offset = 0;
|
||||
switch(spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
tmod_offset = 8;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
tmod_offset = 10;
|
||||
break;
|
||||
}
|
||||
set_bit(&spi_handle->ctrlr0, 3 << tmod_offset, tmod << tmod_offset);
|
||||
}
|
||||
|
||||
static spi_transfer_width_t spi_get_frame_size(uint64 data_bit_length)
|
||||
{
|
||||
if(data_bit_length < 8)
|
||||
return SPI_TRANS_CHAR;
|
||||
else if(data_bit_length < 16)
|
||||
return SPI_TRANS_SHORT;
|
||||
return SPI_TRANS_INT;
|
||||
}
|
||||
|
||||
void spi_send_data_normal(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *tx_buff, uint64 tx_len)
|
||||
{
|
||||
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
|
||||
uint64 index, fifo_len;
|
||||
spi_set_tmod(spi_num, SPI_TMOD_TRANS);
|
||||
|
||||
volatile spi_t *spi_handle = spi[spi_num];
|
||||
|
||||
// uint8 dfs_offset;
|
||||
uint8 dfs_offset = 0;
|
||||
switch(spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
dfs_offset = 16;
|
||||
break;
|
||||
case 2:
|
||||
// configASSERT(!"Spi Bus 2 Not Support!");
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
dfs_offset = 0;
|
||||
break;
|
||||
}
|
||||
uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
|
||||
spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
|
||||
|
||||
uint8 v_misalign_flag = 0;
|
||||
uint32 v_send_data;
|
||||
if((uintptr_t)tx_buff % frame_width)
|
||||
v_misalign_flag = 1;
|
||||
|
||||
spi_handle->ssienr = 0x01;
|
||||
spi_handle->ser = 1U << chip_select;
|
||||
uint32 i = 0;
|
||||
while(tx_len)
|
||||
{
|
||||
fifo_len = 32 - spi_handle->txflr;
|
||||
fifo_len = fifo_len < tx_len ? fifo_len : tx_len;
|
||||
switch(frame_width)
|
||||
{
|
||||
case SPI_TRANS_INT:
|
||||
fifo_len = fifo_len / 4 * 4;
|
||||
if(v_misalign_flag)
|
||||
{
|
||||
for(index = 0; index < fifo_len; index += 4)
|
||||
{
|
||||
// memcpy(&v_send_data, tx_buff + i, 4);
|
||||
memmove(&v_send_data, tx_buff + i, 4);
|
||||
spi_handle->dr[0] = v_send_data;
|
||||
i += 4;
|
||||
}
|
||||
} else
|
||||
{
|
||||
for(index = 0; index < fifo_len / 4; index++)
|
||||
spi_handle->dr[0] = ((uint32 *)tx_buff)[i++];
|
||||
}
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
fifo_len = fifo_len / 2 * 2;
|
||||
if(v_misalign_flag)
|
||||
{
|
||||
for(index = 0; index < fifo_len; index += 2)
|
||||
{
|
||||
// memcpy(&v_send_data, tx_buff + i, 2);
|
||||
memmove(&v_send_data, tx_buff + i, 2);
|
||||
spi_handle->dr[0] = v_send_data;
|
||||
i += 2;
|
||||
}
|
||||
} else
|
||||
{
|
||||
for(index = 0; index < fifo_len / 2; index++)
|
||||
spi_handle->dr[0] = ((uint16 *)tx_buff)[i++];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
spi_handle->dr[0] = tx_buff[i++];
|
||||
break;
|
||||
}
|
||||
tx_len -= fifo_len;
|
||||
}
|
||||
while((spi_handle->sr & 0x05) != 0x04)
|
||||
;
|
||||
spi_handle->ser = 0x00;
|
||||
spi_handle->ssienr = 0x00;
|
||||
}
|
||||
|
||||
void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
|
||||
uint64 cmd_len, const uint8 *tx_buff, uint64 tx_len)
|
||||
{
|
||||
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
// uint8 *v_buf = malloc(cmd_len + tx_len);
|
||||
uint8 *v_buf = kalloc();
|
||||
uint64 i;
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
v_buf[i] = cmd_buff[i];
|
||||
for(i = 0; i < tx_len; i++)
|
||||
v_buf[cmd_len + i] = tx_buff[i];
|
||||
|
||||
spi_send_data_normal(spi_num, chip_select, v_buf, cmd_len + tx_len);
|
||||
// free((void *)v_buf);
|
||||
kfree((void *)v_buf);
|
||||
}
|
||||
|
||||
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8 *cmd_buff,
|
||||
uint64 cmd_len, uint8 *rx_buff, uint64 rx_len)
|
||||
{
|
||||
// configASSERT(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
uint64 index, fifo_len;
|
||||
if(cmd_len == 0)
|
||||
spi_set_tmod(spi_num, SPI_TMOD_RECV);
|
||||
else
|
||||
spi_set_tmod(spi_num, SPI_TMOD_EEROM);
|
||||
volatile spi_t *spi_handle = spi[spi_num];
|
||||
|
||||
// uint8 dfs_offset;
|
||||
uint8 dfs_offset = 0;
|
||||
switch(spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
dfs_offset = 16;
|
||||
break;
|
||||
case 2:
|
||||
// configASSERT(!"Spi Bus 2 Not Support!");
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
dfs_offset = 0;
|
||||
break;
|
||||
}
|
||||
uint32 data_bit_length = (spi_handle->ctrlr0 >> dfs_offset) & 0x1F;
|
||||
spi_transfer_width_t frame_width = spi_get_frame_size(data_bit_length);
|
||||
|
||||
uint32 i = 0;
|
||||
uint64 v_cmd_len = cmd_len / frame_width;
|
||||
uint32 v_rx_len = rx_len / frame_width;
|
||||
|
||||
spi_handle->ctrlr1 = (uint32)(v_rx_len - 1);
|
||||
spi_handle->ssienr = 0x01;
|
||||
|
||||
while(v_cmd_len)
|
||||
{
|
||||
fifo_len = 32 - spi_handle->txflr;
|
||||
fifo_len = fifo_len < v_cmd_len ? fifo_len : v_cmd_len;
|
||||
switch(frame_width)
|
||||
{
|
||||
case SPI_TRANS_INT:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
spi_handle->dr[0] = ((uint32 *)cmd_buff)[i++];
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
spi_handle->dr[0] = ((uint16 *)cmd_buff)[i++];
|
||||
break;
|
||||
default:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
spi_handle->dr[0] = cmd_buff[i++];
|
||||
break;
|
||||
}
|
||||
spi_handle->ser = 1U << chip_select;
|
||||
v_cmd_len -= fifo_len;
|
||||
}
|
||||
|
||||
if(cmd_len == 0)
|
||||
{
|
||||
spi_handle->dr[0] = 0xffffffff;
|
||||
spi_handle->ser = 1U << chip_select;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while(v_rx_len)
|
||||
{
|
||||
fifo_len = spi_handle->rxflr;
|
||||
fifo_len = fifo_len < v_rx_len ? fifo_len : v_rx_len;
|
||||
switch(frame_width)
|
||||
{
|
||||
case SPI_TRANS_INT:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
((uint32 *)rx_buff)[i++] = spi_handle->dr[0];
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
((uint16 *)rx_buff)[i++] = (uint16)spi_handle->dr[0];
|
||||
break;
|
||||
default:
|
||||
for(index = 0; index < fifo_len; index++)
|
||||
rx_buff[i++] = (uint8)spi_handle->dr[0];
|
||||
break;
|
||||
}
|
||||
|
||||
v_rx_len -= fifo_len;
|
||||
}
|
||||
|
||||
spi_handle->ser = 0x00;
|
||||
spi_handle->ssienr = 0x00;
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// Created by lumin on 2020/11/2.
|
||||
//
|
||||
#include <spi.h>
|
||||
#include <sysctl.h>
|
||||
#include <assert.h>
|
||||
#include <util.h>
|
||||
|
||||
volatile spi_t *const spi[4] =
|
||||
{
|
||||
(volatile spi_t *)SPI0_BASE_ADDR,
|
||||
(volatile spi_t *)SPI1_BASE_ADDR,
|
||||
(volatile spi_t *)SPI_SLAVE_BASE_ADDR,
|
||||
(volatile spi_t *)SPI3_BASE_ADDR
|
||||
};
|
||||
|
||||
static void spi_clk_init(uint8_t spi_num);
|
||||
static uint32_t spi_get_ctrlr0(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, size_t data_bit_length);
|
||||
static void spi_set_transfer_mode(uint8_t spi_num, spi_transfer_mode_t tmode);
|
||||
|
||||
void spi_init(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format,
|
||||
size_t data_bit_length, uint32_t endian)
|
||||
{
|
||||
assert(data_bit_length >= SPI_MIN_DATA_BIT_LENGTH && data_bit_length <= SPI_MAX_DATA_BIT_LENGTH);
|
||||
assert(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
|
||||
spi_clk_init(spi_num);
|
||||
|
||||
// init spi controller
|
||||
volatile spi_t *spi_controller = spi[spi_num];
|
||||
if (spi_controller->baudr == 0)
|
||||
spi_controller->baudr = SPI_BAUDRATE_DEFAULT_VAL;
|
||||
spi_controller->imr = SPI_INTERRUPT_DISABLE; // default disable interrupt mode
|
||||
spi_controller->dmacr = SPI_DMACR_DEFAULT_VAL;
|
||||
spi_controller->dmatdlr = SPI_DMATDLR_DEFAULT_VAL;
|
||||
spi_controller->dmardlr = SPI_DMARDLR_DEFAULT_VAL;
|
||||
spi_controller->ser = SPI_SLAVE_DISABLE; // default disable slave
|
||||
spi_controller->ssienr = SPI_MASTER_DISABLE; // default disable master
|
||||
spi_controller->ctrlr0 = spi_get_ctrlr0(spi_num, work_mode, frame_format, data_bit_length);
|
||||
spi_controller->spi_ctrlr0 = SPI_TMOD_DEFAULT_VAL; // default transmit mode
|
||||
spi_controller->endian = endian; // MSB or LSB
|
||||
}
|
||||
|
||||
void spi_send_data_standard(spi_device_num_t spi_num, spi_chip_select_t slave, const uint8_t *tx_buff, size_t tx_len)
|
||||
{
|
||||
assert(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
assert(tx_len != 0);
|
||||
|
||||
// set transfer mode
|
||||
spi_set_transfer_mode(spi_num,SPI_TMODE_TRANS);
|
||||
|
||||
// set register status, begin to transfer
|
||||
volatile spi_t *spi_controller = spi[spi_num];
|
||||
spi_controller->ser = 1U << slave;
|
||||
spi_controller->ssienr = SPI_MASTER_ENABLE;
|
||||
|
||||
// data transmission
|
||||
size_t fifo_len, i;
|
||||
uint32_t cur = 0;
|
||||
while (tx_len)
|
||||
{
|
||||
fifo_len = SPI_FIFO_CAPCITY_IN_BYTE - spi_controller->txflr;
|
||||
if (tx_len < fifo_len)
|
||||
fifo_len = tx_len;
|
||||
|
||||
for (i = 0; i < fifo_len; i++)
|
||||
spi_controller->dr[0] = tx_buff[cur++];
|
||||
tx_len -= fifo_len;
|
||||
}
|
||||
// finish sign
|
||||
while ((spi_controller->sr & 0x05) != 0x04)
|
||||
;
|
||||
|
||||
spi_controller->ser = SPI_SLAVE_DISABLE;
|
||||
spi_controller->ser = SPI_MASTER_DISABLE;
|
||||
}
|
||||
|
||||
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, uint8_t *rx_buff, size_t rx_len)
|
||||
{
|
||||
assert(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
assert(rx_len != 0);
|
||||
|
||||
// set transfer mode
|
||||
spi_set_transfer_mode(spi_num, SPI_TMODE_RECV);
|
||||
|
||||
// set register status, begin to transfer
|
||||
volatile spi_t *spi_controller = spi[spi_num];
|
||||
spi_controller->ctrlr1 = (uint32_t)(rx_len - 1);
|
||||
spi_controller->ssienr = SPI_MASTER_ENABLE;
|
||||
spi_controller->dr[0] = 0xffffffff;
|
||||
spi_controller->ser = 1U << chip_select;
|
||||
|
||||
// data transmission
|
||||
size_t fifo_len;
|
||||
uint32_t cur = 0, i;
|
||||
while (rx_len)
|
||||
{
|
||||
fifo_len = spi_controller->rxflr;
|
||||
if (rx_len < fifo_len)
|
||||
fifo_len = rx_len;
|
||||
|
||||
for (i = 0; i < fifo_len; i++)
|
||||
rx_buff[cur++] = spi_controller->dr[0];
|
||||
rx_len -= fifo_len;
|
||||
}
|
||||
|
||||
spi_controller->ser = SPI_SLAVE_DISABLE;
|
||||
spi_controller->ssienr = SPI_MASTER_DISABLE;
|
||||
}
|
||||
|
||||
uint32_t spi_set_clk_rate(spi_device_num_t spi_num, uint32_t spi_clk)
|
||||
{
|
||||
uint32_t spi_baudr = sysctl_clock_get_freq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_clk;
|
||||
if (spi_baudr < 2)
|
||||
spi_baudr = 2;
|
||||
else if (spi_baudr > 65534)
|
||||
spi_baudr = 65534;
|
||||
volatile spi_t *spi_controller = spi[spi_num];
|
||||
spi_controller->baudr = spi_baudr;
|
||||
return sysctl_clock_get_freq(SYSCTL_CLOCK_SPI0 + spi_num) / spi_clk;
|
||||
}
|
||||
|
||||
static void spi_clk_init(uint8_t spi_num)
|
||||
{
|
||||
assert(spi_num < SPI_DEVICE_MAX && spi_num != 2);
|
||||
if (spi_num == 3)
|
||||
sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1);
|
||||
sysctl_clock_enable(SYSCTL_CLOCK_SPI0 + spi_num);
|
||||
sysctl_clock_set_threshold(SYSCTL_CLOCK_SPI0 + spi_num, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate ctrlr0 from passed arguments
|
||||
*/
|
||||
static uint32_t spi_get_ctrlr0(spi_device_num_t spi_num, spi_work_mode_t work_mode, spi_frame_format_t frame_format, size_t data_bit_length)
|
||||
{
|
||||
uint8_t work_mode_offset, data_bit_length_offset, frame_format_offset;
|
||||
switch (spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
work_mode_offset = SPI01_WORK_MODE_OFFSET;
|
||||
data_bit_length_offset = SPI01_DATA_BIT_LENGTH_OFFSET;
|
||||
frame_format_offset = SPI01_FRAME_FORMAT_OFFSET;
|
||||
break;
|
||||
case 3:
|
||||
work_mode_offset = SPI3_WORK_MODE_OFFSET;
|
||||
data_bit_length_offset = SPI3_DATA_BIT_LENGTH_OFFSET;
|
||||
frame_format_offset = SPI3_FRAME_FORMAT_OFFSET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (frame_format)
|
||||
{
|
||||
case SPI_FF_DUAL:
|
||||
assert(data_bit_length % 2 == 0);
|
||||
break;
|
||||
case SPI_FF_QUAD:
|
||||
assert(data_bit_length % 4 == 0);
|
||||
break;
|
||||
case SPI_FF_OCTAL:
|
||||
assert(data_bit_length % 8 == 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (frame_format << frame_format_offset)
|
||||
| ((data_bit_length - 1) << data_bit_length_offset)
|
||||
| (work_mode << work_mode_offset);
|
||||
}
|
||||
|
||||
static void spi_set_transfer_mode(uint8_t spi_num, spi_transfer_mode_t tmode)
|
||||
{
|
||||
assert(spi_num < SPI_DEVICE_MAX);
|
||||
|
||||
uint8_t tmode_offset;
|
||||
switch (spi_num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
tmode_offset = SPI012_TRANSFER_MODE_OFFSET;
|
||||
break;
|
||||
case 3:
|
||||
tmode_offset = SPI3_TRANSFER_MODE_OFFSET;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
set_bits_value_offset(&spi[spi_num]->ctrlr0, 3, tmode, tmode_offset);
|
||||
}
|
Binary file not shown.
Loading…
Reference in New Issue