tmp commit

This commit is contained in:
retrhelo 2021-01-17 01:23:57 +08:00
parent ee2ee8469e
commit 30afd8a68e
11 changed files with 2103 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

25
kernel/include/vm.h Normal file
View File

@ -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

View File

@ -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

527
kernel/sdcard.back.c Normal file
View File

@ -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;
}

582
kernel/sdcard.example.c Normal file
View File

@ -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");
}

303
kernel/spi.back.c Normal file
View File

@ -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;
}

195
kernel/spi.example.c Normal file
View File

@ -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);
}

BIN
xv6-user/_test Executable file

Binary file not shown.