解释这段代码怎么实现I2C发送的void I2C_SendBytes(I2C_TypeDef *I2Cx, uint8_t *Src, uint32_t len) { DMA_TypeDef *DMAx; _ASSERT(IS_I2C(I2Cx)); _ASSERT(len < 0xfffff); I2Cx->CTRL2.bit.RESTART = I2C_WRITE_FUNC; DMAx = (DMA_TypeDef *)((uint32_t)I2Cx - sizeof(DMA_TypeDef)); DMAx->SRC_ADDR.reg = (uint32_t)Src; DMAx->LEN_LOW.bit.TX_LEN_L = len & 0xffff; DMAx->CTRL.bit.TX_LEN_H = len >> 16; DMAx->LEN_LOW.bit.RX_LEN_L = 0; DMAx->CTRL.bit.RX_LEN_H = 0; DMAx->CTRL.bit.START = 1; while (DMAx->STATUS.bit.DONE != 1); }
时间: 2023-06-12 20:05:19 浏览: 103
这段代码实现了使用DMA进行I2C发送。具体实现步骤如下:
1. 首先进行了一些断言判断,确保传入的I2C和数据长度符合要求。
2. 将I2C的CTRL2寄存器中的RESTART位设置为I2C_WRITE_FUNC,表示接下来要进行I2C写操作。
3. 通过I2Cx指针计算出DMAx指针,因为在STM32系列中,I2C和DMA的寄存器是相邻的,所以可以通过这种方式计算出DMA的寄存器地址。
4. 通过DMAx指针设置DMA的源地址为Src,即要发送的数据缓存区地址。
5. 设置DMA的传输长度为len,即要发送的数据长度。
通过以上步骤,就可以使用DMA进行I2C发送了。这种方法相对于软件方式来说,可以大大提高数据传输的效率和可靠性,特别是在需要大量数据传输的场合下,可以有效减少CPU的占用率。
相关问题
if (usart1_task)//上位机发来数据 { /*编码后发给有人模块(串口8)*/ USART_SendBytes(USART8, usr_buf, encodeing(usart1_buf, usr_buf, usart1_counter, CENTRAL_TO_TERMINAL)); uint8_t data = 0xFF; USART_SendBytes(USART1, &data, 1); waiting_back_tim = 60; waiting_back = 1;//等待回示 usart1_counter = 0; usart1_task = 0; } if (usart8_task)//有人模块发来数据没有处理完,每处理完一帧减一 { /*解码数据,并根据功能码执行*/ rd_fifo_is = 1; while (rd_fifo_is) { fifo_read(&usart8_fifo, &rd_fifo_tmp, 1);//从环队读取一个数据 switch (rd_fifo_tmp)//判断数据内容 { case HEAD: rd_fifo_coun = 0; break; case END: rd_fifo_is = 0; //结束循环 break; case ESCAPE://转义符,下个数据需要转义 escape = 1; break; default: if (escape) { rd_fifo_buf[rd_fifo_coun++] = rd_fifo_tmp ^ 0x30; escape = 0; } else { rd_fifo_buf[rd_fifo_coun++] = rd_fifo_tmp; } break; } }
这也是一段代码,主要是用于处理串口数据的收发。当接收到来自上位机的数据时,代码会对数据进行编码,并通过串口8发送给“有人模块”,并等待“有人模块”的返回。同时,代码会将接收缓冲区计数器清零,并将任务标志位清零。当接收到来自“有人模块”的数据时,代码会对数据进行解码,并根据功能码执行相应的操作。此处使用了FIFO缓冲区来完成数据的读写操作。具体而言,代码会不断从FIFO缓冲区中读取数据,并根据数据内容进行相应的处理,直到读取到结束符(END)为止。并且在解码时,还考虑了转义符(ESCAPE)的情况,从而确保数据的正确性。
uint8_t* payload = &rtpPacket->rtppayload[RTP_HEADER_SIZE]; uint8_t fuHeader = (49 << 1) | ((frame[0]) >> 5); // 分片头部 ((frame[0] & NALU_NRI) >> 5) int remainPktSize = frameSize % rtpPayloadSize; // 剩余不完整包的大小 while (frameSize > rtpPayloadSize) { // 分片发送 memcpy(payload, &fuHeader, 1); memcpy(payload + 1, &frame[1], rtpPayloadSize - 1); ret = RtpSendPacket(socket, ip, port, rtpPacket, rtpPayloadSize); if (ret < 0) { return -1; } rtpPacket->rtpHeader.seq++; sendBytes += ret; // 下一个分片包 frame += rtpPayloadSize - 1; frameSize -= rtpPayloadSize - 1; fuHeader &= ~(1 << 7); // 去掉S标志 } 这段代码对于265分包模式来说 有什么问题么
这段代码在处理H.265分包模式时存在一些问题。以下是问题的详细说明:
1. 不完整包处理:这段代码没有处理最后一个分片包的情况,也就是剩余不完整包的大小(remainPktSize)。在H.265中,最后一个分片可能不是完整的,因为帧大小不一定能被rtpPayloadSize整除。因此,应该在循环结束后处理最后一个分片,而不是简单地忽略它。
2. 分片头部设置:fuHeader变量的计算方式存在问题。根据H.265标准,fuHeader的第一个字节应该包含FU Indicator和FU Header两部分。但是在这段代码中,只使用了一个字节来表示fuHeader,其中只包含了FU Header的值。正确的方法是使用两个字节来表示fuHeader,并将FU Indicator和FU Header放入其中。
3. 分片序列号设置:这段代码在发送每个分片包之后,仅简单地递增了RTP数据包的序列号(seq)。但是,在H.265分包模式中,每个切片都应该具有自己的序列号,而不是简单地递增。因此,应该根据切片的位置和总切片数量来计算和设置每个切片的序列号。
4. 分片标志设置:fuHeader &= ~(1 << 7) 这行代码将去掉S标志位,但是在H.265中,分片头部的S标志位不是简单地去掉就可以的。根据H.265标准,S标志位(Start of Slice)是切片的起始标志,应该根据切片的位置来设置。
综上所述,这段代码在处理H.265分包模式时存在一些问题,需要进行修复和调整,以符合H.265标准要求。修复的方式包括正确设置分片头部、处理不完整包、计算和设置分片序列号等。
阅读全文