STM32学习笔记9——stm32L072 SD卡程序移植记录

16 篇文章 1 订阅

项目使用stm32L072,需要将采样的数据保存到SD卡中。SD卡程序参考ST公司的官方STM32L073Z_EVAL开发板的例程。需要修改的地方如下:
1、 修改stm32L073z_eval.h中SPI的管脚配置、AF配置;
2、 官方开发板使用了一片STM32L152CCT6扩展了STM32L073的IO口,并通过I2C接口连接。在SD卡例程中,扩展IO口用于检测SD卡是否连接好。我们的板子中没有设计SD卡硬件检测的功能,所以在stm32L073z_eval_sd.c的BSP_SD_Init函数中将有关SD卡detect的代码屏蔽,只保留调用SD_IO_Init函数和return。
3、 在stm320L0xx_hal_conf.h中,开启FLASH模块,屏蔽I2C模块。如下:

#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
/* #define HAL_I2C_MODULE_ENABLED */

4、 在stm32l073z_eval.c中SD卡部分有如下语句:

#if defined(HAL_SPI_MODULE_ENABLED) && defined(HAL_I2C_MODULE_ENABLED)

因为开发板中SD卡部分同时用到了SPI和I2C模块,但我们的板子中没用到I2C,所以将上述语句中的I2C屏蔽,即:

#if defined(HAL_SPI_MODULE_ENABLED)  //&& defined(HAL_I2C_MODULE_ENABLED)

至此,源文件基本修改完毕,可以运行程序了。但是在main函数中发现调用函数f_mkfs((TCHAR const*)SDPath, 0, 0);时返回FR_DISK_ERR错误。单步调试发现错误发生在文件dickio.c中的函数disk_write,该函数的定义如下:

#if _USE_WRITE == 1
DRESULT disk_write (
    BYTE pdrv,      /* Physical drive nmuber to identify the drive */
    const BYTE *buff,   /* Data to be written */
    DWORD sector,       /* Sector address in LBA */
    UINT count          /* Number of sectors to write */
)
{
  DRESULT res;

  res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
  return res;
}

这就有点凌乱了,从形式上看,函数disk_write调用了它自己!这个函数是怎么调用底层的SPI写函数,在工程中无论怎么搜索disk_write都未发现。继续单步调试,发现的确跳转到了stm32l073z_eval_sd.c文件中的SD_write函数。那暂时先不管怎么调用的SD_write函数,先找为什么报错吧。继续单步调试,发现SD_write调用BSP_SD_WriteBlocks,在BSP_SD_WriteBlocks中错误发生在如下语句:

ptr = malloc(sizeof(uint8_t)*BlockSize);

哦,是动态分配内存时出错!sizeof(uint8_t)*BlockSize的大小经测试为512,尝试把上述语句直接改为:

ptr = malloc(256);

不再报错。这样,问题就清楚了。是因为动态分配较大的空间时发生错误,而发生错误的原因就是堆栈设置较小。
在启动文件(.s)中将语句

Heap_Size       EQU     0x00000200

改为

Heap_Size       EQU     0x00000400

再次测试,程序通过。烧录程序,执行正常。

最后,还有一个遗留问题。函数disk_write是怎么调用函数SD_write的呢?既然搜索disk_write查不到结果,那就搜索SD_write试试。果然,在sd_diskio.c中发现如下定义:

const Diskio_drvTypeDef  SD_Driver =
{
  SD_initialize,
  SD_status,
  SD_read, 
#if  _USE_WRITE == 1
  SD_write,
#endif /* _USE_WRITE == 1 */

#if  _USE_IOCTL == 1
  SD_ioctl,
#endif /* _USE_IOCTL == 1 */
};

而结构体Diskio_drvTypeDef的定义为:

/** 
  * @brief  Disk IO Driver structure definition  
  */ 
typedef struct
{
  DSTATUS (*disk_initialize) (BYTE);                     /*!< Initialize Disk Drive                     */
  DSTATUS (*disk_status)     (BYTE);                     /*!< Get Disk Status                           */
  DRESULT (*disk_read)       (BYTE, BYTE*, DWORD, UINT);       /*!< Read Sector(s)                            */
#if _USE_WRITE == 1 
  DRESULT (*disk_write)      (BYTE, const BYTE*, DWORD, UINT); /*!< Write Sector(s) when _USE_WRITE = 0       */
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1  
  DRESULT (*disk_ioctl)      (BYTE, BYTE, void*);              /*!< I/O control operation when _USE_IOCTL = 1 */
#endif /* _USE_IOCTL == 1 */

}Diskio_drvTypeDef;

这就说明,SD_Driver是一个结构体,它里面有一个函数指针DRESULT (*disk_write),该指针指向SD_write函数。看来,SD_write函数是通过SD_Driver调用的。搜索SD_Driver,发现在main函数的刚开始有如下语句:

FATFS_LinkDriver( &SD_Driver, SDPath ) == 0

研究下这个函数,就可以发现函数SD_write是通过这个link函数与全局变量disk连接在一起的,然后在函数disk_write中调用。
总结一点就是:
(再把函数disk_write贴一遍)

DRESULT disk_write (
    BYTE pdrv,      /* Physical drive nmuber to identify the drive */
    const BYTE *buff,   /* Data to be written */
    DWORD sector,       /* Sector address in LBA */
    UINT count          /* Number of sectors to write */
)
{
  DRESULT res;

  res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
  return res;
}

函数disk_write中调用的disk_write并不是函数disk_write本身!而是结构体disk.drv中的函数指针,该指针指向了函数SD_write函数。两个disk_write起的名字一样,所以引起了误解。O( ̄) ̄)o

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值