硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1996|回复: 9
收起左侧

[STM32H7] 请教:STM32H743操作SDRAM出现读取数据不对的问题

[复制链接]

3

主题

14

回帖

23

积分

新手上路

积分
23
发表于 2021-12-17 17:00:24 | 显示全部楼层 |阅读模式
在H743上,之前使用SDRAM,都是4字节对齐的。没有遇到问题。但是最近需要非4字节对齐方式使用SDRAM。

1、使用memcpy函数,操作非4字节对齐地址,出错。然后配置MPU
        MPU_InitStruct.Number = MPU_REGION_NUMBER5;
        MPU_InitStruct.Enable = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress = 0xD0000000;
        MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
        MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
        MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
        HAL_MPU_ConfigRegion(&MPU_InitStruct);


2、配置完MPU之后,memcpy不出错了。但是读取非4字节地址开始的一段数据,读的是不对的。按4字节对齐读取数据,就是对的。


请教,在H743上如何才能准确读取非4字节对齐地址开始的一段数据?谢谢
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2021-12-17 19:51:31 | 显示全部楼层
应该是这个帖子的问题,此贴第10条

【烧脑技术贴】无法回避的字节对齐问题,从八个方向深入探讨(变量对齐,栈对齐,DMA对齐,结构体成对齐,Cache, RTOS双堆栈等)
https://www.armbbs.cn/forum.php? ... 9400&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-12-17 20:16:07 | 显示全部楼层
eric2013 发表于 2021-12-17 19:51
应该是这个帖子的问题,此贴第10条

【烧脑技术贴】无法回避的字节对齐问题,从八个方向深入探讨(变量对 ...

把SDRAM存储地址0xD0000000,配置为normal存储类型,硬件异常的问题解决了。但以非4字节对齐方式取数据,取出来的数据不对。程序是不会异常了。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2021-12-18 00:35:54 | 显示全部楼层
你的测试代码是什么样的,分享下,我试试。
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-12-18 08:52:26 | 显示全部楼层
static void tcp_recv_task(void *thread_param)
{
        INT32 recved_len = 0; //已接收的长度
        SOCKET_MNT *socket_mnt = &g_device.socket_mnt;
        socket_mnt->recved_len = 0;
        socket_mnt->recv_buf = tcp_recv_buf;
        UINT8 *start_ptr = socket_mnt->recv_buf; //json起始地址
        UINT8 *current_ptr = socket_mnt->recv_buf;
        BOOL has_find_json_start = FALSE;
        UINT32 count = 0;
       
        osDelay(50); //等主线程完成操作。因为刚开始tcp线程还没建立,要先挂起接收线程,所以延时50ms等初始线程挂起本线程
       
        while(1)
        {
                recved_len = recv(socket_mnt->socket_fd, socket_mnt->recv_buf + socket_mnt->recved_len, TCP_BIG_DATA_BUF_LEN, 0);
                //recved_len = recv(socket_mnt->socket_fd, socket_mnt->recv_buf, TCP_RECV_BUF_LEN, 0);
               
                //socket异常,可能是对端关闭。
                if (recved_len <= 0)
                {
                        //if (errno)
                        {
                                socket_mnt->tcp_status = TCP_DISCONNECTED; //重置socket状态
                                vTaskSuspend(NULL); //挂起任务自身
                        }
                       
                        //恢复状态后,重置变量
                        socket_mnt->recved_len = 0;
                        has_find_json_start = FALSE;
                        start_ptr = socket_mnt->recv_buf;
                        current_ptr = socket_mnt->recv_buf;
                        count = 0;
                       
                        continue;
                }
               
                socket_mnt->recved_len += recved_len;
               
                //SCB_CleanInvalidateDCache_by_Addr((uint32_t *)socket_mnt->recv_buf, 1024 * 10);
               
                write_tcp_msg(socket_mnt->recv_buf, socket_mnt->recved_len);
               
FIND_JSON_START:
                if (!has_find_json_start)
                {
                        //从接收缓冲区socket_mnt->recv_buf开始搜索左花括号,搜索长度是socket_mnt->recved_len
                        start_ptr = socket_mnt->recv_buf;
                       
                        //找json数据的第一个左大括号
                        for (UINT32 i = 0; i < socket_mnt->recved_len; i++)
                        {
                                if ('{' == socket_mnt->recv_buf)
                                {
                                        has_find_json_start = TRUE;
                                        start_ptr = &socket_mnt->recv_buf;
                                        break;
                                }
                        }
                       
                        //没有找到json起点,抛弃这一次数据
                        if (!has_find_json_start)
                        {
                                socket_mnt->recved_len = 0;
                               
                                continue;
                        }
                        else
                        {
                                count = 0;
                        }
                }
               
                //找到json起点
                if (!count) //如果大括号计数为0,从第一个左大括号位置开始搜索。否则就是对端发送半包数据
                {
                        current_ptr = start_ptr;
                }
               
                for (; current_ptr < socket_mnt->recv_buf + socket_mnt->recved_len; current_ptr++)
                {
                        if ('{' == *current_ptr)
                        {
                                count++;
                        }
                        else if ('}' == *current_ptr)
                        {
                                count--;
                        }
                       
                        if (0 == count) //找到一帧数据
                        {
                                //将这一帧数据添加到队列
                                if (!queue_is_full(&socket_mnt->json_msg_queue.queue))
                                {
                                        INT32 tail = queue_get_tail(&socket_mnt->json_msg_queue.queue);
                                        UINT32 data_len = (current_ptr - start_ptr) + 1 + 1; //最后+1,是为了拼凑成字符串
                                        UINT8 *data = (UINT8 *)json_malloc(data_len);
                                        if (data)
                                        {
                                                memset(data, 0, data_len);
                                                memcpy(data, start_ptr, data_len - 1);
                                               
                                                socket_mnt->json_msg_queue.fifo[tail] = data;
                                               
                                                queue_push(&socket_mnt->json_msg_queue.queue);
                                        }
                                }
                               
                                //__packed UINT8* packd_ptr =  socket_mnt->recv_buf;
                               
                                socket_mnt->recved_len -= current_ptr - socket_mnt->recv_buf + 1; //计算剩余长度
                                if (socket_mnt->recved_len)
                                {
                                        UINT8 *data = (UINT8 *)os_malloc(socket_mnt->recved_len);
                                        memset(data, 0, socket_mnt->recved_len);
                                        //UINT8 *tmp = (UINT8*)(current_ptr + 1);
                                        memcpy(data, current_ptr + 1, socket_mnt->recved_len);
                                       
                                        osDelay(200);
                                        write_tcp_msg(socket_mnt->recv_buf, 0x65);
                                        osDelay(200);
                                        write_tcp_msg(current_ptr + 1, socket_mnt->recved_len);
                                        osDelay(200);
                                        //memcpy((void *)socket_mnt->recv_buf, (void *)data, socket_mnt->recved_len);
                                        os_free(data);
                                       
                                        //memcpy((void *)socket_mnt->recv_buf, (void *)(current_ptr + 1), socket_mnt->recved_len); //把剩余的数据挪到缓冲起始地址
                                        write_tcp_msg(socket_mnt->recv_buf, 0x65);
                                }
                               
                                has_find_json_start = FALSE;
                               
                                goto FIND_JSON_START; //重新开始找json起始括号,可以处理粘包情况
                        }
                }
        }
}

socket_mnt->recv_buf是挂接的SDRAM前16M,__attribute__((at(SDRAM_BANK_ADDR))) UINT8 tcp_recv_buf[TCP_BIG_DATA_BUF_LEN] = { 0 };

MPU配置已经贴出来了,配置为normal存储类型

现在的测试结果是,程序不会异常。但是读取一段内存数据,如果不是4字节对齐的地址,读出数据不对,如果是4字节对其地址,读出的就对的。

标注红色的就是测试代码,打印出来。current_ptr是想要读取一段内存的数据,类型是UINT8*

这段代码是接收json消息的代码,处理消息粘包和半包,并且将消息放入消息队列。在处理粘包的时候,需要对数据切片,可能会遇到非4字节对齐的地址
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-12-18 08:57:18 | 显示全部楼层
从0xD0000020地址开始读取一段数据,读出来是对的。从0xD0000021/0xD0000022/0xD0000023等地址读取一段数据,读出来是错的。程序始终不会挂死
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2021-12-18 09:35:23 | 显示全部楼层
kevin_yf 发表于 2021-12-18 08:57
从0xD0000020地址开始读取一段数据,读出来是对的。从0xD0000021/0xD0000022/0xD0000023等地址读取一段数据 ...

这代码太麻烦了,没法测试。

有没有简单点的
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-12-18 10:01:35 | 显示全部楼层
eric2013 发表于 2021-12-18 09:35
这代码太麻烦了,没法测试。

有没有简单点的

找到问题了!在使用SDRAM进行非4字节内存地址操作的时候,不能使用MDK提供的memcpy/memmove函数,自己写一个,读取非4字节地址的数据就对了。
但是,为什么这样就可以了,MDK对memcpy函数做了什么特殊优化吗
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2021-12-18 11:15:13 | 显示全部楼层
kevin_yf 发表于 2021-12-18 10:01
找到问题了!在使用SDRAM进行非4字节内存地址操作的时候,不能使用MDK提供的memcpy/memmove函数,自己写 ...

帮你测试了下,简单使用memcpy没问题。
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
 楼主| 发表于 2021-12-18 11:40:44 | 显示全部楼层
eric2013 发表于 2021-12-18 11:15
帮你测试了下,简单使用memcpy没问题。

谢谢。
我这边用编译器的memcpy测试确实有问题,改成自己实现的就可以了。可能是编译器优化配置问题
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 22:23 , Processed in 0.339114 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表