Skip to content

Commit

Permalink
stmhal: Change 64-bit arithmetic to 32-bit for SD card block addressing.
Browse files Browse the repository at this point in the history
By measuring SD card addresses in blocks and not bytes, one can get away
with using 32-bit numbers.

This patch also uses proper atomic lock/unlock around SD card
read/write, adds SD.info() function, and gives error code for failed
read/writes.
  • Loading branch information
dpgeorge committed Sep 15, 2014
1 parent 6ff42c5 commit 1d7fb82
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 81 deletions.
4 changes: 2 additions & 2 deletions stmhal/diskio.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ DRESULT disk_read (

#if MICROPY_HW_HAS_SDCARD
case PD_SDCARD:
if (!sdcard_read_blocks(buff, sector, count)) {
if (sdcard_read_blocks(buff, sector, count) != 0) {
return RES_ERROR;
}
return RES_OK;
Expand Down Expand Up @@ -160,7 +160,7 @@ DRESULT disk_write (

#if MICROPY_HW_HAS_SDCARD
case PD_SDCARD:
if (!sdcard_write_blocks(buff, sector, count)) {
if (sdcard_write_blocks(buff, sector, count) != 0) {
return RES_ERROR;
}
return RES_OK;
Expand Down
10 changes: 6 additions & 4 deletions stmhal/hal/inc/stm32f4xx_hal_sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,9 @@ void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd);
* @{
*/
/* Blocking mode: Polling */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
// dpgeorge: read/write functions renamed to emphasise that address is given by block number
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr);

/* Non-Blocking mode: Interrupt */
Expand All @@ -646,8 +647,9 @@ void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd);
void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd);

/* Non-Blocking mode: DMA */
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks);
// dpgeorge: read/write functions renamed to emphasise that address is given by block number
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks);
HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout);
/**
Expand Down
56 changes: 40 additions & 16 deletions stmhal/hal/src/stm32f4xx_hal_sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,13 +449,13 @@ __weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd)
* is managed by polling mode.
* @param hsd: SD handle
* @param pReadBuffer: pointer to the buffer that will contain the received data
* @param ReadAddr: Address from where data is to be read
* @param BlockNumber: Block number from where data is to be read (byte address = BlockNumber * BlockSize)
* @param BlockSize: SD card Data block size
* This parameter should be 512
* @param NumberOfBlocks: Number of SD blocks to read
* @retval SD Card error state
*/
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks)
{
SDIO_CmdInitTypeDef sdio_cmdinitstructure;
SDIO_DataInitTypeDef sdio_datainitstructure;
Expand All @@ -465,10 +465,16 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff
/* Initialize data control register */
hsd->Instance->DCTRL = 0;

uint32_t ReadAddr;
if (hsd->CardType == HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
ReadAddr /= 512;
ReadAddr = BlockNumber;
}
else
{
// should not overflow for standard-capacity cards
ReadAddr = BlockNumber * BlockSize;
}

/* Set Block Size for Card */
Expand Down Expand Up @@ -507,7 +513,7 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff
sdio_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
}

sdio_cmdinitstructure.Argument = (uint32_t)ReadAddr;
sdio_cmdinitstructure.Argument = ReadAddr;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);

/* Read block(s) in polling mode */
Expand Down Expand Up @@ -633,13 +639,13 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuff
* transfer is managed by polling mode.
* @param hsd: SD handle
* @param pWriteBuffer: pointer to the buffer that will contain the data to transmit
* @param WriteAddr: Address from where data is to be written
* @param BlockNumber: Block number to where data is to be written (byte address = BlockNumber * BlockSize)
* @param BlockSize: SD card Data block size
* This parameter should be 512.
* @param NumberOfBlocks: Number of SD blocks to write
* @retval SD Card error state
*/
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks)
{
SDIO_CmdInitTypeDef sdio_cmdinitstructure;
SDIO_DataInitTypeDef sdio_datainitstructure;
Expand All @@ -651,10 +657,16 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu
/* Initialize data control register */
hsd->Instance->DCTRL = 0;

uint32_t WriteAddr;
if (hsd->CardType == HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
WriteAddr /= 512;
WriteAddr = BlockNumber;
}
else
{
// should not overflow for standard-capacity cards
WriteAddr = BlockNumber * BlockSize;
}

/* Set Block Size for Card */
Expand Down Expand Up @@ -684,7 +696,7 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu
sdio_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;
}

sdio_cmdinitstructure.Argument = (uint32_t)WriteAddr;
sdio_cmdinitstructure.Argument = WriteAddr;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);

/* Check for error conditions */
Expand Down Expand Up @@ -851,13 +863,13 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBu
* to check the completion of the read process
* @param hsd: SD handle
* @param pReadBuffer: Pointer to the buffer that will contain the received data
* @param ReadAddr: Address from where data is to be read
* @param BlockNumber: Block number from where data is to be read (byte address = BlockNumber * BlockSize)
* @param BlockSize: SD card Data block size
* This paramater should be 512.
* @param NumberOfBlocks: Number of blocks to read.
* @retval SD Card error state
*/
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)
HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks)
{
SDIO_CmdInitTypeDef sdio_cmdinitstructure;
SDIO_DataInitTypeDef sdio_datainitstructure;
Expand Down Expand Up @@ -898,10 +910,16 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead
/* Enable the DMA Stream */
HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)&hsd->Instance->FIFO, (uint32_t)pReadBuffer, (uint32_t)(BlockSize * NumberOfBlocks));

uint32_t ReadAddr;
if (hsd->CardType == HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
ReadAddr /= 512;
ReadAddr = BlockNumber;
}
else
{
// should not overflow for standard-capacity cards
ReadAddr = BlockNumber * BlockSize;
}

/* Set Block Size for Card */
Expand Down Expand Up @@ -941,7 +959,7 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead
sdio_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
}

sdio_cmdinitstructure.Argument = (uint32_t)ReadAddr;
sdio_cmdinitstructure.Argument = ReadAddr;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);

/* Check for error conditions */
Expand All @@ -968,13 +986,13 @@ HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pRead
* to check the completion of the write process (by SD current status polling).
* @param hsd: SD handle
* @param pWriteBuffer: pointer to the buffer that will contain the data to transmit
* @param WriteAddr: Address from where data is to be read
* @param BlockNumber: Block number to where data is to be written (byte address = BlockNumber * BlockSize)
* @param BlockSize: the SD card Data block size
* This parameter should be 512.
* @param NumberOfBlocks: Number of blocks to write
* @retval SD Card error state
*/
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks)
HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_BlockNumber_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint32_t BlockNumber, uint32_t BlockSize, uint32_t NumberOfBlocks)
{
SDIO_CmdInitTypeDef sdio_cmdinitstructure;
SDIO_DataInitTypeDef sdio_datainitstructure;
Expand Down Expand Up @@ -1015,10 +1033,16 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWri
/* Enable SDIO DMA transfer */
__HAL_SD_SDIO_DMA_ENABLE();

uint32_t WriteAddr;
if (hsd->CardType == HIGH_CAPACITY_SD_CARD)
{
BlockSize = 512;
WriteAddr /= 512;
WriteAddr = BlockNumber;
}
else
{
// should not overflow for standard-capacity cards
WriteAddr = BlockNumber * BlockSize;
}

/* Set Block Size for Card */
Expand Down Expand Up @@ -1049,7 +1073,7 @@ HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWri
sdio_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK;
}

sdio_cmdinitstructure.Argument = (uint32_t)WriteAddr;
sdio_cmdinitstructure.Argument = WriteAddr;
SDIO_SendCommand(hsd->Instance, &sdio_cmdinitstructure);

/* Check for error conditions */
Expand Down
100 changes: 57 additions & 43 deletions stmhal/sdcard.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,54 +141,46 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
return cardinfo.CardCapacity;
}

bool sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
// check that dest pointer is aligned on a 4-byte boundary
if (((uint32_t)dest & 3) != 0) {
return false;
return SD_ERROR;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return false;
return SD_ERROR;
}

// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it fill up in the middle of a read.
// This will not be needed when SD uses DMA for transfer.
__disable_irq();
HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks(&sd_handle, (uint32_t*)dest, (uint64_t)block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, num_blocks);
__enable_irq();
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_ReadBlocks_BlockNumber(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);

if (err != SD_OK) {
return false;
}

return true;
return err;
}

bool sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
// check that src pointer is aligned on a 4-byte boundary
if (((uint32_t)src & 3) != 0) {
return false;
return SD_ERROR;
}

// check that SD card is initialised
if (sd_handle.Instance == NULL) {
return false;
return SD_ERROR;
}

// We must disable IRQs because the SDIO peripheral has a small FIFO
// buffer and we can't let it drain to empty in the middle of a write.
// This will not be needed when SD uses DMA for transfer.
__disable_irq();
HAL_SD_ErrorTypedef err = HAL_SD_WriteBlocks(&sd_handle, (uint32_t*)src, (uint64_t)block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, num_blocks);
__enable_irq();

if (err != SD_OK) {
return false;
}
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
HAL_SD_ErrorTypedef err = HAL_SD_WriteBlocks_BlockNumber(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
MICROPY_END_ATOMIC_SECTION(atomic_state);

return true;
return err;
}

#if 0
Expand All @@ -205,7 +197,7 @@ bool sdcard_read_blocks_dma(uint8_t *dest, uint32_t block_num, uint32_t num_bloc
}

// do the read
if (HAL_SD_ReadBlocks_DMA(&sd_handle, (uint32_t*)dest, (uint64_t)block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE) != SD_OK) {
if (HAL_SD_ReadBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)dest, block_num, SDCARD_BLOCK_SIZE) != SD_OK) {
return false;
}

Expand All @@ -230,7 +222,7 @@ bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t nu

SD_Error status;

status = HAL_SD_WriteBlock_DMA(&sd_handle, (uint32_t*)src, (uint64_t)block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE, num_blocks);
status = HAL_SD_WriteBlocks_BlockNumber_DMA(&sd_handle, (uint32_t*)src, block_num, SDCARD_BLOCK_SIZE, num_blocks);
if (status != SD_OK) {
return false;
}
Expand All @@ -247,14 +239,17 @@ bool sdcard_write_blocks_dma(const uint8_t *src, uint32_t block_num, uint32_t nu

/******************************************************************************/
// Micro Python bindings
//
// Note: these function are a bit ad-hoc at the moment and are mainly intended
// for testing purposes. In the future SD should be a proper class with a
// consistent interface and methods to mount/unmount it.

static mp_obj_t sd_present(mp_obj_t self) {
STATIC mp_obj_t sd_present(mp_obj_t self) {
return MP_BOOL(sdcard_is_present());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_present_obj, sd_present);

static MP_DEFINE_CONST_FUN_OBJ_1(sd_present_obj, sd_present);

static mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) {
STATIC mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) {
bool result;
if (mp_obj_is_true(state)) {
result = sdcard_power_on();
Expand All @@ -264,40 +259,59 @@ static mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) {
}
return MP_BOOL(result);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power);

static MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power);
STATIC mp_obj_t sd_info(mp_obj_t self) {
HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo);
if (sd_handle.Instance == NULL) {
return mp_const_none;
}
HAL_SD_CardInfoTypedef cardinfo;
HAL_SD_Get_CardInfo(&sd_handle, &cardinfo);
// cardinfo.SD_csd and cardinfo.SD_cid have lots of info but we don't use them
mp_obj_t tuple[3] = {
mp_obj_new_int_from_ull(cardinfo.CardCapacity),
mp_obj_new_int_from_uint(cardinfo.CardBlockSize),
mp_obj_new_int(cardinfo.CardType),
};
return mp_obj_new_tuple(3, tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info);

static mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
STATIC mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
uint8_t *dest = m_new(uint8_t, SDCARD_BLOCK_SIZE);
if (!sdcard_read_blocks(dest, mp_obj_get_int(block_num), 1)) {
mp_uint_t ret = sdcard_read_blocks(dest, mp_obj_get_int(block_num), 1);

if (ret != 0) {
m_free(dest, SDCARD_BLOCK_SIZE);
return mp_const_none;
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_read_blocks failed [%u]", ret));
}

return mp_obj_new_bytearray_by_ref(SDCARD_BLOCK_SIZE, dest);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);

static MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);

static mp_obj_t sd_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t source) {
STATIC mp_obj_t sd_write(mp_obj_t self, mp_obj_t block_num, mp_obj_t data) {
mp_buffer_info_t bufinfo;
uint8_t tmp[1];

pyb_buf_get_for_send(source, &bufinfo, tmp);
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len % SDCARD_BLOCK_SIZE != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writes must be aligned to SDCARD_BLOCK_SIZE (%d) bytes", SDCARD_BLOCK_SIZE));
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "writes must be a multiple of %d bytes", SDCARD_BLOCK_SIZE));
}

if (!sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_write_blocks failed"));
mp_uint_t ret = sdcard_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / SDCARD_BLOCK_SIZE);

if (ret != 0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "sdcard_write_blocks failed [%u]", ret));
}

return mp_const_none;
}

static MP_DEFINE_CONST_FUN_OBJ_3(sd_write_obj, sd_write);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(sd_write_obj, sd_write);

STATIC const mp_map_elem_t sdcard_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_present), (mp_obj_t)&sd_present_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_power), (mp_obj_t)&sd_power_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&sd_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&sd_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&sd_write_obj },
};
Expand Down
Loading

0 comments on commit 1d7fb82

Please sign in to comment.