STM32CubeMx入门教程(9):SDIO接口DMA模式应用

导语“我们在前面章节中使用了sdio接口对sd卡进行读写操作,使用的轮询模式,这种模式效率低下,f103有sdio接口的dma模式,dma模式在不需要cpu操作的情况下,自动的将数据进行读取和写入。”
第一节 系统要求同第八章。
第二节 cubemx配置sdio配置为4位的总线模式。
在dma的配置中,sdio的dma通道只有一个,所以读和写之间需要进行方向改变。地址增长选择内存,这是因为我们把sdio外设的数据发送到内存中,或从内存中读入数据。
在nvic中断配置中,设置sdio的中断优先级比dma的优先级高。
玩成上述配置后,进行代码生成。
第三节 mdk代码编写在stm32f103 中sdio的dma只有一个通道,因此读写是公用的,需要在读写之前进行方向配置,不能简单的调用halsdreadblocksdma()库函数来完成读,不能简单的调用halsdwriteblocksdma()来完成写操作。我们编写dioreadblocksdma()、sdiowriteblocksdma()来使用dma模式。
(1)sdio.h
/* user code begin private defines */extern dma_handletypedef hdma_sdio;/* user code end private defines *//* user code begin prototypes */ hal_statustypedef sdio_readblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks); hal_statustypedef sdio_writeblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks); /* user code end prototypes */在sdio.c中/* user code begin 1 */ hal_statustypedef sdio_readblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks) { hal_statustypedef return_status; hal_sd_cardstatetypedef sd_card_status; do { sd_card_status = hal_sd_getcardstate(hsd); }while(sd_card_status != hal_sd_card_transfer ); /* sdio dma deinit */ /* sdio deinit */ hal_dma_deinit(&hdma_sdio); /* 改变dma的方向,重新初始化 */ hdma_sdio.instance = dma2_channel4; hdma_sdio.init.direction = dma_periph_to_memory; hdma_sdio.init.periphinc = dma_pinc_disable; hdma_sdio.init.meminc = dma_minc_enable; hdma_sdio.init.periphdataalignment = dma_pdataalign_word; hdma_sdio.init.memdataalignment = dma_mdataalign_word; hdma_sdio.init.mode = dma_normal; hdma_sdio.init.priority = dma_priority_low; if (hal_dma_init(&hdma_sdio) != hal_ok) { error_handler(); } __hal_linkdma( hsd,hdmarx,hdma_sdio); return_status = hal_sd_readblocks_dma( hsd,pdata, blockadd, numberofblocks); return return_status; } hal_statustypedef sdio_writeblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks) { hal_statustypedef return_status; hal_sd_cardstatetypedef sd_card_status; do { sd_card_status = hal_sd_getcardstate(hsd); }while(sd_card_status != hal_sd_card_transfer ); /* sdio dma deinit */ /* sdio deinit */ hal_dma_deinit(&hdma_sdio); /* 改变dma的方向,重新初始化 */ hdma_sdio.instance = dma2_channel4; hdma_sdio.init.direction = dma_memory_to_periph; hdma_sdio.init.periphinc = dma_pinc_disable; hdma_sdio.init.meminc = dma_minc_enable; hdma_sdio.init.periphdataalignment = dma_pdataalign_word; hdma_sdio.init.memdataalignment = dma_mdataalign_word; hdma_sdio.init.mode = dma_normal; hdma_sdio.init.priority = dma_priority_low; if (hal_dma_init(&hdma_sdio) != hal_ok) { error_handler(); } __hal_linkdma(hsd,hdmatx,hdma_sdio); return_status = hal_sd_writeblocks_dma(hsd,pdata, blockadd, numberofblocks); return return_status; }在min.c中
/*sd 操作*/typedef enum {failed = 0, passed = !failed} teststatus;/* 私有宏定义 ----------------------------------------------------------------*/#define block_size 512 // sd卡块大小 #define number_of_blocks 8 // 测试块数量(小于15)#define write_read_address 0x00002000 // 测试读写地址#define sdmmc hsd/* 私有变量 ------------------------------------------------------------------*/__align(4) uint32_t buffer_block_tx[block_size*number_of_blocks]; // 写数据缓存__align(4) uint32_t buffer_block_rx[block_size*number_of_blocks]; // 读数据缓存hal_statustypedef sd_status; // hal库函数操作sd卡函数返回值:操作结果teststatus test_status; // 数据测试结果void sd_erasetest_dma();void sd_write_read_test_dma();hal_statustypedef return_status;hal_sd_cardstatetypedef sd_card_status;hal_dma_statetypedef dma_status;在mian函数中:
//申明测试函数 sd_erasetest_dma(); sd_write_read_test_dma();在main.c
/*************************************/teststatus ebuffercmp(uint32_t* pbuffer, uint32_t bufferlength){ while (bufferlength--) { /* sd卡擦除后的可能值为0xff或0 */ if ((*pbuffer != 0xffffffff) && (*pbuffer != 0)) { return failed; } pbuffer++; } return passed;}void sd_erasetest_dma(void){ /* 第1个参数为sd卡句柄,第2个参数为擦除起始地址,第3个参数为擦除结束地址 */ sd_status=hal_sd_erase(&sdmmc,write_read_address,write_read_address+number_of_blocks*4); printf(《sd》erase status:%drn,sd_status); hal_delay(500); if (sd_status == hal_ok) { /* 读取刚刚擦除的区域 */ sd_status = sdio_readblocks_dma(&sdmmc,(uint8_t *)buffer_block_rx,write_read_address,number_of_blocks); printf(《sd》erase read status:%drn,sd_status); /* 把擦除区域读出来对比 */ test_status = ebuffercmp(buffer_block_rx,block_size*number_of_blocks); if(test_status == passed) printf(《sd》除测试成功!rn ); else printf(《sd》擦除不成功,数据出错!rn ); } else { printf(《sd》擦除测试失败!部分sd不支持擦除,只要读写测试通过即可rn ); }}void fill_buffer(uint32_t *pbuffer, uint32_t bufferlength, uint32_t offset){ uint32_t index = 0; /* 填充数据 */ for (index = 0; index < bufferlength; index++ ) { pbuffer[index] = index + offset; }}teststatus buffercmp(uint32_t* pbuffer1, uint32_t* pbuffer2, uint32_t bufferlength){ while (bufferlength--) { if(bufferlength%50==0) { printf(buf:0x%08x - 0x%08xrn,*pbuffer1,*pbuffer2); } if (*pbuffer1 != *pbuffer2) { return failed; } pbuffer1++; pbuffer2++; } return passed;}void sd_write_read_test_dma(void){ printf( warning: this program may erase all the tf card data. rn); printf(rn initialize sd card successfully!rnrn); printf( sd card information! rn); printf( cardcapacity : %llu rn,((unsigned long long)sdmmc.sdcard.blocksize*hsd.sdcard.blocknbr)); printf( cardblocksize : %d rn,sdmmc.sdcard.blocksize); printf( rca : %d rn,sdmmc.sdcard.relcardadd); printf( cardtype : %d rn,sdmmc.sdcard.cardtype); int i,j = 0; /* 填充数据到写缓存 */ fill_buffer(buffer_block_tx,block_size*number_of_blocks, 0x6666); /* 往sd卡写入数据 */ sd_status = sdio_writeblocks_dma(&sdmmc,(uint8_t *)buffer_block_tx,write_read_address,number_of_blocks); printf(《sd》write status:%drn,sd_status); hal_delay(600); /* 从sd卡读取数据 */ sd_status = sdio_readblocks_dma(&sdmmc,(uint8_t *)buffer_block_rx,write_read_address,number_of_blocks); printf(《sd》read status:%drn,sd_status); /* 比较数据 */ test_status = buffercmp(buffer_block_tx, buffer_block_rx, block_size*number_of_blocks/4); //比较 if(test_status == passed) { printf(《sd》》读写测试成功!rn ); for(i=0;i第四节 效果演示
可以看到能够正确的使用dma进行sd卡的读写操作。
第五节 补充dma 补充我们在上一节中使用dma的使用读写过程中要改变dma的方向,在每个读写函数中进行,可以单独实现:
在sdio.h
hal_statustypedef sd_dmaconfigrx(sd_handletypedef *hsd);hal_statustypedef sd_dmaconfigtx(sd_handletypedef *hsd);hal_statustypedef sdio_readblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks);hal_statustypedef sdio_writeblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks);在sdio.c 中
hal_statustypedef sdio_readblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks){ hal_statustypedef return_status; hal_sd_cardstatetypedef sd_card_status; do { sd_card_status = hal_sd_getcardstate(hsd); }while(sd_card_status != hal_sd_card_transfer ); if (sd_dmaconfigrx(hsd) != hal_ok) { return hal_error; } else { return_status = hal_sd_readblocks_dma( hsd,pdata, blockadd, numberofblocks); return return_status; }}hal_statustypedef sdio_writeblocks_dma(sd_handletypedef *hsd, uint8_t *pdata, uint32_t blockadd, uint32_t numberofblocks){ hal_statustypedef return_status; hal_sd_cardstatetypedef sd_card_status; do { sd_card_status = hal_sd_getcardstate(hsd); }while(sd_card_status != hal_sd_card_transfer ); if (sd_dmaconfigtx(hsd) != hal_ok) { return hal_error; } else { return_status = hal_sd_writeblocks_dma(hsd,pdata, blockadd, numberofblocks); return return_status; }}hal_statustypedef sd_dmaconfigrx(sd_handletypedef *hsd){ hal_statustypedef status = hal_error; hdma_sdio.instance = dma2_channel4; hdma_sdio.init.direction = dma_periph_to_memory; hdma_sdio.init.periphinc = dma_pinc_disable; hdma_sdio.init.meminc = dma_minc_enable; hdma_sdio.init.periphdataalignment = dma_pdataalign_word; hdma_sdio.init.memdataalignment = dma_mdataalign_word; hdma_sdio.init.mode = dma_normal; hdma_sdio.init.priority = dma_priority_low; __hal_linkdma( hsd,hdmarx,hdma_sdio); hal_dma_abort(&hdma_sdio); hal_dma_deinit(&hdma_sdio); status = hal_dma_init(&hdma_sdio); return status;}hal_statustypedef sd_dmaconfigtx(sd_handletypedef *hsd){ hal_statustypedef status = hal_error; hdma_sdio.instance = dma2_channel4; hdma_sdio.init.direction = dma_memory_to_periph; hdma_sdio.init.periphinc = dma_pinc_disable; hdma_sdio.init.meminc = dma_minc_enable; hdma_sdio.init.periphdataalignment = dma_pdataalign_word; hdma_sdio.init.memdataalignment = dma_mdataalign_word; hdma_sdio.init.mode = dma_normal; hdma_sdio.init.priority = dma_priority_low; __hal_linkdma( hsd,hdmarx,hdma_sdio); hal_dma_abort(&hdma_sdio); hal_dma_deinit(&hdma_sdio); status = hal_dma_init(&hdma_sdio); return status;}

基于DSP的自动对焦系统
为什么PCB上要有晶振​?晶振的类型和作用
如何用buck改buck-boost拓扑输出负压
三星移动商用开通官网咨询服务 助力企业“非常时期”业务开展
Google宣布停止研发可以检测眼泪中血糖水平的隐形眼镜
STM32CubeMx入门教程(9):SDIO接口DMA模式应用
中兴通讯提出基于TITAN平台的AO重构方案
iphone8什么时候上市多少钱?iPhone8线下已开始预订!32G价格6288起,要不要考虑一下华为mate10?
三星s8什么时候上市?三星s8最新消息:堆料狂魔?三星S8的造价成本,比肩小米6的售价!
中国电信实测5G通信性能,荣耀手机整体领先
受5G推动移动DRAM 内存制造商2020年冲刺成长
苹果现款iPod touch将配备4英寸Retina视网膜屏幕搭载A8芯片
0.6μm CMOS工艺全差分运算放大器的设计
数据中心服务器功率一般多大 数据中心服务器操作系统三大类包括
什么模式下操作降压转换器最好
基于DDK的TLV320AIC23音频编解码器驱动程序设计
四通道高速直接数字频率合成器AD9959的功能特点和应用
鸿海的面板工厂再陷亏损 夏普电视难与中国电视竞争
关于汽车线束测试,你了解多少?
艾拉比芮亚楠:当OTA普及,我们将在物联网和车联网看到三个变化