cam_hal.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. // Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdalign.h>
  17. #include "esp_heap_caps.h"
  18. #include "ll_cam.h"
  19. #include "cam_hal.h"
  20. #if (ESP_IDF_VERSION_MAJOR == 3) && (ESP_IDF_VERSION_MINOR == 3)
  21. #include "rom/ets_sys.h"
  22. #else
  23. #include "esp_timer.h"
  24. #if CONFIG_IDF_TARGET_ESP32
  25. #include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
  26. #elif CONFIG_IDF_TARGET_ESP32S2
  27. #include "esp32s2/rom/ets_sys.h"
  28. #elif CONFIG_IDF_TARGET_ESP32S3
  29. #include "esp32s3/rom/ets_sys.h"
  30. #endif
  31. #endif // ESP_IDF_VERSION_MAJOR
  32. #define ESP_CAMERA_ETS_PRINTF ets_printf
  33. #if CONFIG_CAMERA_TASK_STACK_SIZE
  34. #define CAM_TASK_STACK CONFIG_CAMERA_TASK_STACK_SIZE
  35. #else
  36. #define CAM_TASK_STACK (2*1024)
  37. #endif
  38. static const char *TAG = "cam_hal";
  39. static cam_obj_t *cam_obj = NULL;
  40. static const uint32_t JPEG_SOI_MARKER = 0xFFD8FF; // written in little-endian for esp32
  41. static const uint16_t JPEG_EOI_MARKER = 0xD9FF; // written in little-endian for esp32
  42. static int cam_verify_jpeg_soi(const uint8_t *inbuf, uint32_t length)
  43. {
  44. for (uint32_t i = 0; i < length; i++) {
  45. if (memcmp(&inbuf[i], &JPEG_SOI_MARKER, 3) == 0) {
  46. //ESP_LOGW(TAG, "SOI: %d", (int) i);
  47. return i;
  48. }
  49. }
  50. ESP_LOGW(TAG, "NO-SOI");
  51. return -1;
  52. }
  53. static int cam_verify_jpeg_eoi(const uint8_t *inbuf, uint32_t length)
  54. {
  55. int offset = -1;
  56. uint8_t *dptr = (uint8_t *)inbuf + length - 2;
  57. while (dptr > inbuf) {
  58. if (memcmp(dptr, &JPEG_EOI_MARKER, 2) == 0) {
  59. offset = dptr - inbuf;
  60. //ESP_LOGW(TAG, "EOI: %d", length - (offset + 2));
  61. return offset;
  62. }
  63. dptr--;
  64. }
  65. return -1;
  66. }
  67. static bool cam_get_next_frame(int * frame_pos)
  68. {
  69. if(!cam_obj->frames[*frame_pos].en){
  70. for (int x = 0; x < cam_obj->frame_cnt; x++) {
  71. if (cam_obj->frames[x].en) {
  72. *frame_pos = x;
  73. return true;
  74. }
  75. }
  76. } else {
  77. return true;
  78. }
  79. return false;
  80. }
  81. static bool cam_start_frame(int * frame_pos)
  82. {
  83. if (cam_get_next_frame(frame_pos)) {
  84. if(ll_cam_start(cam_obj, *frame_pos)){
  85. // Vsync the frame manually
  86. ll_cam_do_vsync(cam_obj);
  87. uint64_t us = (uint64_t)esp_timer_get_time();
  88. cam_obj->frames[*frame_pos].fb.timestamp.tv_sec = us / 1000000UL;
  89. cam_obj->frames[*frame_pos].fb.timestamp.tv_usec = us % 1000000UL;
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken)
  96. {
  97. if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) {
  98. ll_cam_stop(cam);
  99. cam->state = CAM_STATE_IDLE;
  100. ESP_CAMERA_ETS_PRINTF(DRAM_STR("cam_hal: EV-%s-OVF\r\n"), cam_event==CAM_IN_SUC_EOF_EVENT ? DRAM_STR("EOF") : DRAM_STR("VSYNC"));
  101. }
  102. }
  103. //Copy fram from DMA dma_buffer to fram dma_buffer
  104. static void cam_task(void *arg)
  105. {
  106. int cnt = 0;
  107. int frame_pos = 0;
  108. cam_obj->state = CAM_STATE_IDLE;
  109. cam_event_t cam_event = 0;
  110. xQueueReset(cam_obj->event_queue);
  111. while (1) {
  112. xQueueReceive(cam_obj->event_queue, (void *)&cam_event, portMAX_DELAY);
  113. DBG_PIN_SET(1);
  114. switch (cam_obj->state) {
  115. case CAM_STATE_IDLE: {
  116. if (cam_event == CAM_VSYNC_EVENT) {
  117. //DBG_PIN_SET(1);
  118. if(cam_start_frame(&frame_pos)){
  119. cam_obj->frames[frame_pos].fb.len = 0;
  120. cam_obj->state = CAM_STATE_READ_BUF;
  121. }
  122. cnt = 0;
  123. }
  124. }
  125. break;
  126. case CAM_STATE_READ_BUF: {
  127. camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb;
  128. size_t pixels_per_dma = (cam_obj->dma_half_buffer_size * cam_obj->fb_bytes_per_pixel) / (cam_obj->dma_bytes_per_item * cam_obj->in_bytes_per_pixel);
  129. if (cam_event == CAM_IN_SUC_EOF_EVENT) {
  130. if(!cam_obj->psram_mode){
  131. if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
  132. ESP_LOGW(TAG, "FB-OVF");
  133. ll_cam_stop(cam_obj);
  134. DBG_PIN_SET(0);
  135. continue;
  136. }
  137. frame_buffer_event->len += ll_cam_memcpy(cam_obj,
  138. &frame_buffer_event->buf[frame_buffer_event->len],
  139. &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
  140. cam_obj->dma_half_buffer_size);
  141. }
  142. //Check for JPEG SOI in the first buffer. stop if not found
  143. if (cam_obj->jpeg_mode && cnt == 0 && cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len) != 0) {
  144. ll_cam_stop(cam_obj);
  145. cam_obj->state = CAM_STATE_IDLE;
  146. }
  147. cnt++;
  148. } else if (cam_event == CAM_VSYNC_EVENT) {
  149. //DBG_PIN_SET(1);
  150. ll_cam_stop(cam_obj);
  151. if (cnt || !cam_obj->jpeg_mode || cam_obj->psram_mode) {
  152. if (cam_obj->jpeg_mode) {
  153. if (!cam_obj->psram_mode) {
  154. if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
  155. ESP_LOGW(TAG, "FB-OVF");
  156. cnt--;
  157. } else {
  158. frame_buffer_event->len += ll_cam_memcpy(cam_obj,
  159. &frame_buffer_event->buf[frame_buffer_event->len],
  160. &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
  161. cam_obj->dma_half_buffer_size);
  162. }
  163. }
  164. cnt++;
  165. }
  166. cam_obj->frames[frame_pos].en = 0;
  167. if (cam_obj->psram_mode) {
  168. if (cam_obj->jpeg_mode) {
  169. frame_buffer_event->len = cnt * cam_obj->dma_half_buffer_size;
  170. } else {
  171. frame_buffer_event->len = cam_obj->recv_size;
  172. }
  173. } else if (!cam_obj->jpeg_mode) {
  174. if (frame_buffer_event->len != cam_obj->fb_size) {
  175. cam_obj->frames[frame_pos].en = 1;
  176. ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, (unsigned) cam_obj->fb_size);
  177. }
  178. }
  179. //send frame
  180. if(!cam_obj->frames[frame_pos].en && xQueueSend(cam_obj->frame_buffer_queue, (void *)&frame_buffer_event, 0) != pdTRUE) {
  181. //pop frame buffer from the queue
  182. camera_fb_t * fb2 = NULL;
  183. if(xQueueReceive(cam_obj->frame_buffer_queue, &fb2, 0) == pdTRUE) {
  184. //push the new frame to the end of the queue
  185. if (xQueueSend(cam_obj->frame_buffer_queue, (void *)&frame_buffer_event, 0) != pdTRUE) {
  186. cam_obj->frames[frame_pos].en = 1;
  187. ESP_LOGE(TAG, "FBQ-SND");
  188. }
  189. //free the popped buffer
  190. cam_give(fb2);
  191. } else {
  192. //queue is full and we could not pop a frame from it
  193. cam_obj->frames[frame_pos].en = 1;
  194. ESP_LOGE(TAG, "FBQ-RCV");
  195. }
  196. }
  197. }
  198. if(!cam_start_frame(&frame_pos)){
  199. cam_obj->state = CAM_STATE_IDLE;
  200. } else {
  201. cam_obj->frames[frame_pos].fb.len = 0;
  202. }
  203. cnt = 0;
  204. }
  205. }
  206. break;
  207. }
  208. DBG_PIN_SET(0);
  209. }
  210. }
  211. static lldesc_t * allocate_dma_descriptors(uint32_t count, uint16_t size, uint8_t * buffer)
  212. {
  213. lldesc_t *dma = (lldesc_t *)heap_caps_malloc(count * sizeof(lldesc_t), MALLOC_CAP_DMA);
  214. if (dma == NULL) {
  215. return dma;
  216. }
  217. for (int x = 0; x < count; x++) {
  218. dma[x].size = size;
  219. dma[x].length = 0;
  220. dma[x].sosf = 0;
  221. dma[x].eof = 0;
  222. dma[x].owner = 1;
  223. dma[x].buf = (buffer + size * x);
  224. dma[x].empty = (uint32_t)&dma[(x + 1) % count];
  225. }
  226. return dma;
  227. }
  228. static esp_err_t cam_dma_config(const camera_config_t *config)
  229. {
  230. bool ret = ll_cam_dma_sizes(cam_obj);
  231. if (0 == ret) {
  232. return ESP_FAIL;
  233. }
  234. cam_obj->dma_node_cnt = (cam_obj->dma_buffer_size) / cam_obj->dma_node_buffer_size; // Number of DMA nodes
  235. cam_obj->frame_copy_cnt = cam_obj->recv_size / cam_obj->dma_half_buffer_size; // Number of interrupted copies, ping-pong copy
  236. ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
  237. (int) cam_obj->dma_buffer_size, (int) cam_obj->dma_half_buffer_size, (int) cam_obj->dma_node_buffer_size,
  238. (int) cam_obj->dma_node_cnt, (int) cam_obj->frame_copy_cnt);
  239. cam_obj->dma_buffer = NULL;
  240. cam_obj->dma = NULL;
  241. cam_obj->frames = (cam_frame_t *)heap_caps_aligned_calloc(alignof(cam_frame_t), 1, cam_obj->frame_cnt * sizeof(cam_frame_t), MALLOC_CAP_DEFAULT);
  242. CAM_CHECK(cam_obj->frames != NULL, "frames malloc failed", ESP_FAIL);
  243. uint8_t dma_align = 0;
  244. size_t fb_size = cam_obj->fb_size;
  245. if (cam_obj->psram_mode) {
  246. dma_align = ll_cam_get_dma_align(cam_obj);
  247. if (cam_obj->fb_size < cam_obj->recv_size) {
  248. fb_size = cam_obj->recv_size;
  249. }
  250. }
  251. /* Allocate memory for frame buffer */
  252. size_t alloc_size = fb_size * sizeof(uint8_t) + dma_align;
  253. uint32_t _caps = MALLOC_CAP_8BIT;
  254. if (CAMERA_FB_IN_DRAM == config->fb_location) {
  255. _caps |= MALLOC_CAP_INTERNAL;
  256. } else {
  257. _caps |= MALLOC_CAP_SPIRAM;
  258. }
  259. for (int x = 0; x < cam_obj->frame_cnt; x++) {
  260. cam_obj->frames[x].dma = NULL;
  261. cam_obj->frames[x].fb_offset = 0;
  262. cam_obj->frames[x].en = 0;
  263. ESP_LOGI(TAG, "Allocating %d Byte frame buffer in %s", alloc_size, _caps & MALLOC_CAP_SPIRAM ? "PSRAM" : "OnBoard RAM");
  264. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
  265. // In IDF v4.2 and earlier, memory returned by heap_caps_aligned_alloc must be freed using heap_caps_aligned_free.
  266. // And heap_caps_aligned_free is deprecated on v4.3.
  267. cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_aligned_alloc(16, alloc_size, _caps);
  268. #else
  269. cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(alloc_size, _caps);
  270. #endif
  271. CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
  272. if (cam_obj->psram_mode) {
  273. //align PSRAM buffer. TODO: save the offset so proper address can be freed later
  274. cam_obj->frames[x].fb_offset = dma_align - ((uint32_t)cam_obj->frames[x].fb.buf & (dma_align - 1));
  275. cam_obj->frames[x].fb.buf += cam_obj->frames[x].fb_offset;
  276. ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (unsigned) cam_obj->frames[x].fb.buf);
  277. cam_obj->frames[x].dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->frames[x].fb.buf);
  278. CAM_CHECK(cam_obj->frames[x].dma != NULL, "frame dma malloc failed", ESP_FAIL);
  279. }
  280. cam_obj->frames[x].en = 1;
  281. }
  282. if (!cam_obj->psram_mode) {
  283. cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
  284. if(NULL == cam_obj->dma_buffer) {
  285. ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
  286. (int) cam_obj->dma_buffer_size, (int) heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
  287. return ESP_FAIL;
  288. }
  289. cam_obj->dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->dma_buffer);
  290. CAM_CHECK(cam_obj->dma != NULL, "dma malloc failed", ESP_FAIL);
  291. }
  292. return ESP_OK;
  293. }
  294. esp_err_t cam_init(const camera_config_t *config)
  295. {
  296. CAM_CHECK(NULL != config, "config pointer is invalid", ESP_ERR_INVALID_ARG);
  297. esp_err_t ret = ESP_OK;
  298. cam_obj = (cam_obj_t *)heap_caps_calloc(1, sizeof(cam_obj_t), MALLOC_CAP_DMA);
  299. CAM_CHECK(NULL != cam_obj, "lcd_cam object malloc error", ESP_ERR_NO_MEM);
  300. cam_obj->swap_data = 0;
  301. cam_obj->vsync_pin = config->pin_vsync;
  302. cam_obj->vsync_invert = true;
  303. ll_cam_set_pin(cam_obj, config);
  304. ret = ll_cam_config(cam_obj, config);
  305. CAM_CHECK_GOTO(ret == ESP_OK, "ll_cam initialize failed", err);
  306. #if CAMERA_DBG_PIN_ENABLE
  307. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[DBG_PIN_NUM], PIN_FUNC_GPIO);
  308. gpio_set_direction(DBG_PIN_NUM, GPIO_MODE_OUTPUT);
  309. gpio_set_pull_mode(DBG_PIN_NUM, GPIO_FLOATING);
  310. #endif
  311. ESP_LOGI(TAG, "cam init ok");
  312. return ESP_OK;
  313. err:
  314. free(cam_obj);
  315. cam_obj = NULL;
  316. return ESP_FAIL;
  317. }
  318. esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint16_t sensor_pid)
  319. {
  320. CAM_CHECK(NULL != config, "config pointer is invalid", ESP_ERR_INVALID_ARG);
  321. esp_err_t ret = ESP_OK;
  322. ret = ll_cam_set_sample_mode(cam_obj, (pixformat_t)config->pixel_format, config->xclk_freq_hz, sensor_pid);
  323. CAM_CHECK_GOTO(ret == ESP_OK, "ll_cam_set_sample_mode failed", err);
  324. cam_obj->jpeg_mode = config->pixel_format == PIXFORMAT_JPEG;
  325. #if CONFIG_IDF_TARGET_ESP32
  326. cam_obj->psram_mode = false;
  327. #else
  328. cam_obj->psram_mode = (config->xclk_freq_hz == 16000000);
  329. #endif
  330. cam_obj->frame_cnt = config->fb_count;
  331. cam_obj->width = resolution[frame_size].width;
  332. cam_obj->height = resolution[frame_size].height;
  333. if(cam_obj->jpeg_mode){
  334. #ifdef CONFIG_CAMERA_JPEG_MODE_FRAME_SIZE_AUTO
  335. cam_obj->recv_size = cam_obj->width * cam_obj->height / 5;
  336. #else
  337. cam_obj->recv_size = CONFIG_CAMERA_JPEG_MODE_FRAME_SIZE;
  338. #endif
  339. cam_obj->fb_size = cam_obj->recv_size;
  340. } else {
  341. cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel;
  342. cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
  343. }
  344. ret = cam_dma_config(config);
  345. CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);
  346. size_t queue_size = cam_obj->dma_half_buffer_cnt - 1;
  347. if (queue_size == 0) {
  348. queue_size = 1;
  349. }
  350. cam_obj->event_queue = xQueueCreate(queue_size, sizeof(cam_event_t));
  351. CAM_CHECK_GOTO(cam_obj->event_queue != NULL, "event_queue create failed", err);
  352. size_t frame_buffer_queue_len = cam_obj->frame_cnt;
  353. if (config->grab_mode == CAMERA_GRAB_LATEST && cam_obj->frame_cnt > 1) {
  354. frame_buffer_queue_len = cam_obj->frame_cnt - 1;
  355. }
  356. cam_obj->frame_buffer_queue = xQueueCreate(frame_buffer_queue_len, sizeof(camera_fb_t*));
  357. CAM_CHECK_GOTO(cam_obj->frame_buffer_queue != NULL, "frame_buffer_queue create failed", err);
  358. ret = ll_cam_init_isr(cam_obj);
  359. CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);
  360. #if CONFIG_CAMERA_CORE0
  361. xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
  362. #elif CONFIG_CAMERA_CORE1
  363. xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
  364. #else
  365. xTaskCreate(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
  366. #endif
  367. ESP_LOGI(TAG, "cam config ok");
  368. return ESP_OK;
  369. err:
  370. cam_deinit();
  371. return ESP_FAIL;
  372. }
  373. esp_err_t cam_deinit(void)
  374. {
  375. if (!cam_obj) {
  376. return ESP_FAIL;
  377. }
  378. cam_stop();
  379. if (cam_obj->task_handle) {
  380. vTaskDelete(cam_obj->task_handle);
  381. }
  382. if (cam_obj->event_queue) {
  383. vQueueDelete(cam_obj->event_queue);
  384. }
  385. if (cam_obj->frame_buffer_queue) {
  386. vQueueDelete(cam_obj->frame_buffer_queue);
  387. }
  388. ll_cam_deinit(cam_obj);
  389. if (cam_obj->dma) {
  390. free(cam_obj->dma);
  391. }
  392. if (cam_obj->dma_buffer) {
  393. free(cam_obj->dma_buffer);
  394. }
  395. if (cam_obj->frames) {
  396. for (int x = 0; x < cam_obj->frame_cnt; x++) {
  397. free(cam_obj->frames[x].fb.buf - cam_obj->frames[x].fb_offset);
  398. if (cam_obj->frames[x].dma) {
  399. free(cam_obj->frames[x].dma);
  400. }
  401. }
  402. free(cam_obj->frames);
  403. }
  404. free(cam_obj);
  405. cam_obj = NULL;
  406. return ESP_OK;
  407. }
  408. void cam_stop(void)
  409. {
  410. ll_cam_vsync_intr_enable(cam_obj, false);
  411. ll_cam_stop(cam_obj);
  412. }
  413. void cam_start(void)
  414. {
  415. ll_cam_vsync_intr_enable(cam_obj, true);
  416. }
  417. camera_fb_t *cam_take(TickType_t timeout)
  418. {
  419. camera_fb_t *dma_buffer = NULL;
  420. TickType_t start = xTaskGetTickCount();
  421. xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout);
  422. #if CONFIG_IDF_TARGET_ESP32S3
  423. // Currently (22.01.2024) there is a bug in ESP-IDF v5.2, that causes
  424. // GDMA to fall into a strange state if it is running while WiFi STA is connecting.
  425. // This code tries to reset GDMA if frame is not received, to try and help with
  426. // this case. It is possible to have some side effects too, though none come to mind
  427. if (!dma_buffer) {
  428. ll_cam_dma_reset(cam_obj);
  429. xQueueReceive(cam_obj->frame_buffer_queue, (void *)&dma_buffer, timeout);
  430. }
  431. #endif
  432. if (dma_buffer) {
  433. if(cam_obj->jpeg_mode){
  434. // find the end marker for JPEG. Data after that can be discarded
  435. int offset_e = cam_verify_jpeg_eoi(dma_buffer->buf, dma_buffer->len);
  436. if (offset_e >= 0) {
  437. // adjust buffer length
  438. dma_buffer->len = offset_e + sizeof(JPEG_EOI_MARKER);
  439. return dma_buffer;
  440. } else {
  441. ESP_LOGW(TAG, "NO-EOI");
  442. cam_give(dma_buffer);
  443. TickType_t ticks_spent = xTaskGetTickCount() - start;
  444. if (ticks_spent >= timeout) {
  445. return NULL; /* We are out of time */
  446. }
  447. return cam_take(timeout - ticks_spent);//recurse!!!!
  448. }
  449. } else if(cam_obj->psram_mode && cam_obj->in_bytes_per_pixel != cam_obj->fb_bytes_per_pixel){
  450. //currently this is used only for YUV to GRAYSCALE
  451. dma_buffer->len = ll_cam_memcpy(cam_obj, dma_buffer->buf, dma_buffer->buf, dma_buffer->len);
  452. }
  453. return dma_buffer;
  454. } else {
  455. ESP_LOGW(TAG, "Failed to get the frame on time!");
  456. // #if CONFIG_IDF_TARGET_ESP32S3
  457. // ll_cam_dma_print_state(cam_obj);
  458. // #endif
  459. }
  460. return NULL;
  461. }
  462. void cam_give(camera_fb_t *dma_buffer)
  463. {
  464. for (int x = 0; x < cam_obj->frame_cnt; x++) {
  465. if (&cam_obj->frames[x].fb == dma_buffer) {
  466. cam_obj->frames[x].en = 1;
  467. break;
  468. }
  469. }
  470. }
  471. void cam_give_all(void) {
  472. for (int x = 0; x < cam_obj->frame_cnt; x++) {
  473. cam_obj->frames[x].en = 1;
  474. }
  475. }