2025-05-13 1:24 AM - edited 2025-05-13 3:59 AM
Hello!
I am using STM32F427VIT6 and OV5640 camera to stream MJPEG to a webserver. I used DCMI DMA to get a jpeg_frame, size around 10KB to 25KB per image, with almost 30FPS and send it to jpeg buffer in CCMRAM like this.
__attribute__((section(".ccmram"))) __attribute__((aligned(32))) uint8_t jpeg[32768];
__attribute__((section(".ccmram"))) __attribute__((aligned(32))) uint32_t jpegLength = 0;
Then I used LwIP with raw TCP, tcp_write() function to send it to webserver but it's very laggy, sometimes return ERR_MEM in this function
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
goto memerr;
Although I spent nearly 100% of my RAM allocating for LwIP heap memory and SND buffer. Here is my LwIP mem config
/*----- Default Value for MEMP_NUM_TCP_PCB: 5 ---*/
#define MEMP_NUM_TCP_PCB 1
/*----- Value in opt.h for NO_SYS: 0 -----*/
#define NO_SYS 1
/*----- Value in opt.h for SYS_LIGHTWEIGHT_PROT: 1 -----*/
#define SYS_LIGHTWEIGHT_PROT 0
/*----- Value in opt.h for MEM_ALIGNMENT: 1 -----*/
#define MEM_ALIGNMENT 4
/*----- Default Value for MEM_SIZE: 1600 ---*/
#define MEM_SIZE 32768
/*----- Default Value for MEMP_NUM_TCP_SEG: 16 ---*/
#define MEMP_NUM_TCP_SEG 2048
/*----- Default Value for PBUF_POOL_SIZE: 16 ---*/
#define PBUF_POOL_SIZE 20
/*----- Default Value for PBUF_POOL_BUFSIZE: 592 ---*/
#define PBUF_POOL_BUFSIZE 1560
/*----- Value in opt.h for LWIP_ETHERNET: LWIP_ARP || PPPOE_SUPPORT -*/
#define LWIP_ETHERNET 1
/*----- Value in opt.h for LWIP_DNS_SECURE: (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT) -*/
#define LWIP_DNS_SECURE 7
/*----- Default Value for TCP_WND: 5840 ---*/
#define TCP_WND 16384
/*----- Default Value for TCP_MSS: 536 ---*/
#define TCP_MSS 1460
/*----- Default Value for TCP_SND_BUF: 2920 ---*/
#define TCP_SND_BUF 16384
/*----- Default Value for TCP_SND_QUEUELEN: 46 ---*/
#define TCP_SND_QUEUELEN 2048
Here is my send_jpeg function
void http_send_jpeg(struct tcp_pcb *pcb)
{
err_t err;
// Nếu chưa đang gửi JPEG, bắt đầu gửi frame mới
if (!jpeg_state.sending)
{
jpeg_state.sent = 0;
jpeg_state.sending = true;
jpeg_state.current_length = jpegLength;
// Gửi header MJPEG
char header[128];
sprintf(header, "--frame\r\nContent-Type: image/jpeg\r\nContent-Length: %lu\r\n\r\n", jpegLength);
// Kiểm tra buffer trước khi gửi header
if (tcp_sndbuf(pcb) < strlen(header))
{
printf("Not enough buffer for header\n");
return;
}
err = tcp_write(pcb, header, strlen(header), TCP_WRITE_FLAG_COPY);
if (err != ERR_OK)
{
printf("tcp_write header failed: %d\n", err);
jpeg_state.sending = false;
return;
}
}
err = ERR_OK;
// Gửi dữ liệu cho đến khi hết buffer hoặc hết dữ liệu
while (jpeg_state.sent < jpeg_state.current_length && err == ERR_OK)
{
// Tính số byte thực sự sẽ gửi
uint16_t to_send = min(16384, jpeg_state.current_length - jpeg_state.sent);
// Gửi dữ liệu
err = tcp_write(pcb, &jpeg[jpeg_state.sent], to_send, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK)
{
printf("tcp_write JPEG failed at: %lu, error: %d\n", jpeg_state.sent, err);
tcp_output(pcb);
return; // Thoát và thử lại sau
}
// Chỉ cập nhật số byte đã gửi khi tcp_write thành công
jpeg_state.sent += to_send;
if (jpeg_state.sent == jpeg_state.current_length)
{
tcp_output(pcb); // Đẩy dữ liệu ngay lập tức
}
}
if (jpeg_state.sent < jpeg_state.current_length)
{
}
else if (tcp_sndbuf(pcb) < 2)
{
// Không đủ buffer cho footer, đợi callback tiếp theo
tcp_output(pcb);
return;
}
else
{
err = tcp_write(pcb, "\r\n", 2, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK)
{
printf("tcp_write footer failed: %d\n", err);
jpeg_state.sending = false;
return;
}
tcp_output(pcb);
jpeg_state.sending = false; // Đánh dấu đã gửi xong
jpeg_state.sent = 0; // Reset vị trí gửi
}
}
sent_callback:
err_t http_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
// Sau khi mỗi phần được gửi thành công
if (tpcb != NULL)
{
// Tiếp tục gửi
http_send_jpeg(tpcb);
}
return ERR_OK;
}
And here is my build log
[build] Memory region Used Size Region Size %age Used
[build] RAM: 190256 B 192 KB 96.77%
[build] CCMRAM: 32776 B 64 KB 50.01%
[build] FLASH: 172004 B 2 MB 8.20%
[driver] Build completed: 00:00:09.461
[build] Build finished with exit code 0
Help me please. I spent too much time on this MJPEG server and still cannot figure it out.