ll_cam.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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 "soc/i2s_struct.h"
  17. #include "esp_idf_version.h"
  18. #if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR > 1)
  19. #include "hal/gpio_ll.h"
  20. #else
  21. #include "soc/gpio_periph.h"
  22. #define esp_rom_delay_us ets_delay_us
  23. static inline int gpio_ll_get_level(gpio_dev_t *hw, int gpio_num)
  24. {
  25. if (gpio_num < 32) {
  26. return (hw->in >> gpio_num) & 0x1;
  27. } else {
  28. return (hw->in1.data >> (gpio_num - 32)) & 0x1;
  29. }
  30. }
  31. #endif
  32. #include "ll_cam.h"
  33. #include "xclk.h"
  34. #include "cam_hal.h"
  35. #if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR >= 3)
  36. #include "esp_rom_gpio.h"
  37. #endif
  38. #if (ESP_IDF_VERSION_MAJOR >= 5)
  39. #define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
  40. #define GPIO_PIN_INTR_NEGEDGE GPIO_INTR_NEGEDGE
  41. #define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
  42. #endif
  43. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 2)
  44. #define ets_delay_us esp_rom_delay_us
  45. #endif
  46. static const char *TAG = "esp32 ll_cam";
  47. #define I2S_ISR_ENABLE(i) {I2S0.int_clr.i = 1;I2S0.int_ena.i = 1;}
  48. #define I2S_ISR_DISABLE(i) {I2S0.int_ena.i = 0;I2S0.int_clr.i = 1;}
  49. typedef union {
  50. struct {
  51. uint32_t sample2:8;
  52. uint32_t unused2:8;
  53. uint32_t sample1:8;
  54. uint32_t unused1:8;
  55. };
  56. uint32_t val;
  57. } dma_elem_t;
  58. typedef enum {
  59. /* camera sends byte sequence: s1, s2, s3, s4, ...
  60. * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ...
  61. */
  62. SM_0A0B_0B0C = 0,
  63. /* camera sends byte sequence: s1, s2, s3, s4, ...
  64. * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ...
  65. */
  66. SM_0A0B_0C0D = 1,
  67. /* camera sends byte sequence: s1, s2, s3, s4, ...
  68. * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ...
  69. */
  70. SM_0A00_0B00 = 3,
  71. } i2s_sampling_mode_t;
  72. typedef size_t (*dma_filter_t)(uint8_t* dst, const uint8_t* src, size_t len);
  73. static i2s_sampling_mode_t sampling_mode = SM_0A00_0B00;
  74. static size_t ll_cam_bytes_per_sample(i2s_sampling_mode_t mode)
  75. {
  76. switch(mode) {
  77. case SM_0A00_0B00:
  78. return 4;
  79. case SM_0A0B_0B0C:
  80. return 4;
  81. case SM_0A0B_0C0D:
  82. return 2;
  83. default:
  84. assert(0 && "invalid sampling mode");
  85. return 0;
  86. }
  87. }
  88. static size_t IRAM_ATTR ll_cam_dma_filter_jpeg(uint8_t* dst, const uint8_t* src, size_t len)
  89. {
  90. const dma_elem_t* dma_el = (const dma_elem_t*)src;
  91. size_t elements = len / sizeof(dma_elem_t);
  92. size_t end = elements / 4;
  93. // manually unrolling 4 iterations of the loop here
  94. for (size_t i = 0; i < end; ++i) {
  95. dst[0] = dma_el[0].sample1;
  96. dst[1] = dma_el[1].sample1;
  97. dst[2] = dma_el[2].sample1;
  98. dst[3] = dma_el[3].sample1;
  99. dma_el += 4;
  100. dst += 4;
  101. }
  102. return elements;
  103. }
  104. static size_t IRAM_ATTR ll_cam_dma_filter_grayscale(uint8_t* dst, const uint8_t* src, size_t len)
  105. {
  106. const dma_elem_t* dma_el = (const dma_elem_t*)src;
  107. size_t elements = len / sizeof(dma_elem_t);
  108. size_t end = elements / 4;
  109. for (size_t i = 0; i < end; ++i) {
  110. // manually unrolling 4 iterations of the loop here
  111. dst[0] = dma_el[0].sample1;
  112. dst[1] = dma_el[1].sample1;
  113. dst[2] = dma_el[2].sample1;
  114. dst[3] = dma_el[3].sample1;
  115. dma_el += 4;
  116. dst += 4;
  117. }
  118. return elements;
  119. }
  120. static size_t IRAM_ATTR ll_cam_dma_filter_grayscale_highspeed(uint8_t* dst, const uint8_t* src, size_t len)
  121. {
  122. const dma_elem_t* dma_el = (const dma_elem_t*)src;
  123. size_t elements = len / sizeof(dma_elem_t);
  124. size_t end = elements / 8;
  125. for (size_t i = 0; i < end; ++i) {
  126. // manually unrolling 4 iterations of the loop here
  127. dst[0] = dma_el[0].sample1;
  128. dst[1] = dma_el[2].sample1;
  129. dst[2] = dma_el[4].sample1;
  130. dst[3] = dma_el[6].sample1;
  131. dma_el += 8;
  132. dst += 4;
  133. }
  134. // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling
  135. if ((elements & 0x7) != 0) {
  136. dst[0] = dma_el[0].sample1;
  137. dst[1] = dma_el[2].sample1;
  138. elements += 1;
  139. }
  140. return elements / 2;
  141. }
  142. static size_t IRAM_ATTR ll_cam_dma_filter_yuyv(uint8_t* dst, const uint8_t* src, size_t len)
  143. {
  144. const dma_elem_t* dma_el = (const dma_elem_t*)src;
  145. size_t elements = len / sizeof(dma_elem_t);
  146. size_t end = elements / 4;
  147. for (size_t i = 0; i < end; ++i) {
  148. dst[0] = dma_el[0].sample1;//y0
  149. dst[1] = dma_el[0].sample2;//u
  150. dst[2] = dma_el[1].sample1;//y1
  151. dst[3] = dma_el[1].sample2;//v
  152. dst[4] = dma_el[2].sample1;//y0
  153. dst[5] = dma_el[2].sample2;//u
  154. dst[6] = dma_el[3].sample1;//y1
  155. dst[7] = dma_el[3].sample2;//v
  156. dma_el += 4;
  157. dst += 8;
  158. }
  159. return elements * 2;
  160. }
  161. static size_t IRAM_ATTR ll_cam_dma_filter_yuyv_highspeed(uint8_t* dst, const uint8_t* src, size_t len)
  162. {
  163. const dma_elem_t* dma_el = (const dma_elem_t*)src;
  164. size_t elements = len / sizeof(dma_elem_t);
  165. size_t end = elements / 8;
  166. for (size_t i = 0; i < end; ++i) {
  167. dst[0] = dma_el[0].sample1;//y0
  168. dst[1] = dma_el[1].sample1;//u
  169. dst[2] = dma_el[2].sample1;//y1
  170. dst[3] = dma_el[3].sample1;//v
  171. dst[4] = dma_el[4].sample1;//y0
  172. dst[5] = dma_el[5].sample1;//u
  173. dst[6] = dma_el[6].sample1;//y1
  174. dst[7] = dma_el[7].sample1;//v
  175. dma_el += 8;
  176. dst += 8;
  177. }
  178. if ((elements & 0x7) != 0) {
  179. dst[0] = dma_el[0].sample1;//y0
  180. dst[1] = dma_el[1].sample1;//u
  181. dst[2] = dma_el[2].sample1;//y1
  182. dst[3] = dma_el[2].sample2;//v
  183. elements += 4;
  184. }
  185. return elements;
  186. }
  187. static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
  188. {
  189. //DBG_PIN_SET(1);
  190. cam_obj_t *cam = (cam_obj_t *)arg;
  191. BaseType_t HPTaskAwoken = pdFALSE;
  192. // filter
  193. ets_delay_us(1);
  194. if (gpio_ll_get_level(&GPIO, cam->vsync_pin) == !cam->vsync_invert) {
  195. ll_cam_send_event(cam, CAM_VSYNC_EVENT, &HPTaskAwoken);
  196. if (HPTaskAwoken == pdTRUE) {
  197. portYIELD_FROM_ISR();
  198. }
  199. }
  200. //DBG_PIN_SET(0);
  201. }
  202. static void IRAM_ATTR ll_cam_dma_isr(void *arg)
  203. {
  204. //DBG_PIN_SET(1);
  205. cam_obj_t *cam = (cam_obj_t *)arg;
  206. BaseType_t HPTaskAwoken = pdFALSE;
  207. typeof(I2S0.int_st) status = I2S0.int_st;
  208. if (status.val == 0) {
  209. return;
  210. }
  211. I2S0.int_clr.val = status.val;
  212. if (status.in_suc_eof) {
  213. ll_cam_send_event(cam, CAM_IN_SUC_EOF_EVENT, &HPTaskAwoken);
  214. }
  215. if (HPTaskAwoken == pdTRUE) {
  216. portYIELD_FROM_ISR();
  217. }
  218. //DBG_PIN_SET(0);
  219. }
  220. bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam)
  221. {
  222. I2S0.conf.rx_start = 0;
  223. I2S_ISR_DISABLE(in_suc_eof);
  224. I2S0.in_link.stop = 1;
  225. return true;
  226. }
  227. esp_err_t ll_cam_deinit(cam_obj_t *cam)
  228. {
  229. gpio_isr_handler_remove(cam->vsync_pin);
  230. if (cam->cam_intr_handle) {
  231. esp_intr_free(cam->cam_intr_handle);
  232. cam->cam_intr_handle = NULL;
  233. }
  234. return ESP_OK;
  235. }
  236. bool ll_cam_start(cam_obj_t *cam, int frame_pos)
  237. {
  238. I2S0.conf.rx_start = 0;
  239. I2S_ISR_ENABLE(in_suc_eof);
  240. I2S0.conf.rx_reset = 1;
  241. I2S0.conf.rx_reset = 0;
  242. I2S0.conf.rx_fifo_reset = 1;
  243. I2S0.conf.rx_fifo_reset = 0;
  244. I2S0.lc_conf.in_rst = 1;
  245. I2S0.lc_conf.in_rst = 0;
  246. I2S0.lc_conf.ahbm_fifo_rst = 1;
  247. I2S0.lc_conf.ahbm_fifo_rst = 0;
  248. I2S0.lc_conf.ahbm_rst = 1;
  249. I2S0.lc_conf.ahbm_rst = 0;
  250. I2S0.rx_eof_num = cam->dma_half_buffer_size / sizeof(dma_elem_t);
  251. I2S0.in_link.addr = ((uint32_t)&cam->dma[0]) & 0xfffff;
  252. I2S0.in_link.start = 1;
  253. I2S0.conf.rx_start = 1;
  254. return true;
  255. }
  256. esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
  257. {
  258. // Enable and configure I2S peripheral
  259. periph_module_enable(PERIPH_I2S0_MODULE);
  260. I2S0.conf.rx_reset = 1;
  261. I2S0.conf.rx_reset = 0;
  262. I2S0.conf.rx_fifo_reset = 1;
  263. I2S0.conf.rx_fifo_reset = 0;
  264. I2S0.lc_conf.in_rst = 1;
  265. I2S0.lc_conf.in_rst = 0;
  266. I2S0.lc_conf.ahbm_fifo_rst = 1;
  267. I2S0.lc_conf.ahbm_fifo_rst = 0;
  268. I2S0.lc_conf.ahbm_rst = 1;
  269. I2S0.lc_conf.ahbm_rst = 0;
  270. I2S0.conf.rx_slave_mod = 1;
  271. I2S0.conf.rx_right_first = 0;
  272. I2S0.conf.rx_msb_right = 0;
  273. I2S0.conf.rx_msb_shift = 0;
  274. I2S0.conf.rx_mono = 0;
  275. I2S0.conf.rx_short_sync = 0;
  276. I2S0.conf2.lcd_en = 1;
  277. I2S0.conf2.camera_en = 1;
  278. // Configure clock divider
  279. I2S0.clkm_conf.clkm_div_a = 0;
  280. I2S0.clkm_conf.clkm_div_b = 0;
  281. I2S0.clkm_conf.clkm_div_num = 2;
  282. I2S0.fifo_conf.dscr_en = 1;
  283. I2S0.fifo_conf.rx_fifo_mod = sampling_mode;
  284. I2S0.fifo_conf.rx_fifo_mod_force_en = 1;
  285. I2S0.conf_chan.rx_chan_mod = 1;
  286. I2S0.sample_rate_conf.rx_bits_mod = 0;
  287. I2S0.timing.val = 0;
  288. I2S0.timing.rx_dsync_sw = 1;
  289. return ESP_OK;
  290. }
  291. void ll_cam_vsync_intr_enable(cam_obj_t *cam, bool en)
  292. {
  293. if (en) {
  294. gpio_intr_enable(cam->vsync_pin);
  295. } else {
  296. gpio_intr_disable(cam->vsync_pin);
  297. }
  298. }
  299. esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config)
  300. {
  301. gpio_config_t io_conf = {0};
  302. io_conf.intr_type = cam->vsync_invert ? GPIO_PIN_INTR_NEGEDGE : GPIO_PIN_INTR_POSEDGE;
  303. io_conf.pin_bit_mask = 1ULL << config->pin_vsync;
  304. io_conf.mode = GPIO_MODE_INPUT;
  305. io_conf.pull_up_en = 1;
  306. io_conf.pull_down_en = 0;
  307. gpio_config(&io_conf);
  308. gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM);
  309. gpio_isr_handler_add(config->pin_vsync, ll_cam_vsync_isr, cam);
  310. gpio_intr_disable(config->pin_vsync);
  311. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_pclk], PIN_FUNC_GPIO);
  312. gpio_set_direction(config->pin_pclk, GPIO_MODE_INPUT);
  313. gpio_set_pull_mode(config->pin_pclk, GPIO_FLOATING);
  314. gpio_matrix_in(config->pin_pclk, I2S0I_WS_IN_IDX, false);
  315. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_vsync], PIN_FUNC_GPIO);
  316. gpio_set_direction(config->pin_vsync, GPIO_MODE_INPUT);
  317. gpio_set_pull_mode(config->pin_vsync, GPIO_FLOATING);
  318. gpio_matrix_in(config->pin_vsync, I2S0I_V_SYNC_IDX, false);
  319. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_href], PIN_FUNC_GPIO);
  320. gpio_set_direction(config->pin_href, GPIO_MODE_INPUT);
  321. gpio_set_pull_mode(config->pin_href, GPIO_FLOATING);
  322. gpio_matrix_in(config->pin_href, I2S0I_H_SYNC_IDX, false);
  323. int data_pins[8] = {
  324. config->pin_d0, config->pin_d1, config->pin_d2, config->pin_d3, config->pin_d4, config->pin_d5, config->pin_d6, config->pin_d7,
  325. };
  326. for (int i = 0; i < 8; i++) {
  327. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[data_pins[i]], PIN_FUNC_GPIO);
  328. gpio_set_direction(data_pins[i], GPIO_MODE_INPUT);
  329. gpio_set_pull_mode(data_pins[i], GPIO_FLOATING);
  330. gpio_matrix_in(data_pins[i], I2S0I_DATA_IN0_IDX + i, false);
  331. }
  332. gpio_matrix_in(0x38, I2S0I_H_ENABLE_IDX, false);
  333. return ESP_OK;
  334. }
  335. esp_err_t ll_cam_init_isr(cam_obj_t *cam)
  336. {
  337. return esp_intr_alloc(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, ll_cam_dma_isr, cam, &cam->cam_intr_handle);
  338. }
  339. void ll_cam_do_vsync(cam_obj_t *cam)
  340. {
  341. }
  342. uint8_t ll_cam_get_dma_align(cam_obj_t *cam)
  343. {
  344. return 0;
  345. }
  346. static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
  347. size_t dma_half_buffer_max = CONFIG_CAMERA_DMA_BUFFER_SIZE_MAX / 2 / cam->dma_bytes_per_item;
  348. size_t dma_buffer_max = 2 * dma_half_buffer_max;
  349. size_t node_max = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE / cam->dma_bytes_per_item;
  350. size_t line_width = cam->width * cam->in_bytes_per_pixel;
  351. size_t image_size = cam->height * line_width;
  352. if (image_size > (4 * 1024 * 1024) || (line_width > dma_half_buffer_max)) {
  353. ESP_LOGE(TAG, "Resolution too high");
  354. return 0;
  355. }
  356. size_t node_size = node_max;
  357. size_t nodes_per_line = 1;
  358. size_t lines_per_node = 1;
  359. size_t lines_per_half_buffer = 1;
  360. size_t dma_half_buffer_min = node_max;
  361. size_t dma_half_buffer = dma_half_buffer_max;
  362. size_t dma_buffer_size = dma_buffer_max;
  363. // Calculate DMA Node Size so that it's divisable by or divisor of the line width
  364. if(line_width >= node_max){
  365. // One or more nodes will be requied for one line
  366. for(size_t i = node_max; i > 0; i=i-1){
  367. if ((line_width % i) == 0) {
  368. node_size = i;
  369. nodes_per_line = line_width / node_size;
  370. break;
  371. }
  372. }
  373. } else {
  374. // One or more lines can fit into one node
  375. for(size_t i = node_max; i > 0; i=i-1){
  376. if ((i % line_width) == 0) {
  377. node_size = i;
  378. lines_per_node = node_size / line_width;
  379. while((cam->height % lines_per_node) != 0){
  380. lines_per_node = lines_per_node - 1;
  381. node_size = lines_per_node * line_width;
  382. }
  383. break;
  384. }
  385. }
  386. }
  387. // Calculate minimum EOF size = max(mode_size, line_size)
  388. dma_half_buffer_min = node_size * nodes_per_line;
  389. // Calculate max EOF size divisable by node size
  390. dma_half_buffer = (dma_half_buffer_max / dma_half_buffer_min) * dma_half_buffer_min;
  391. // Adjust EOF size so that height will be divisable by the number of lines in each EOF
  392. lines_per_half_buffer = dma_half_buffer / line_width;
  393. while((cam->height % lines_per_half_buffer) != 0){
  394. dma_half_buffer = dma_half_buffer - dma_half_buffer_min;
  395. lines_per_half_buffer = dma_half_buffer / line_width;
  396. }
  397. // Calculate DMA size
  398. dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
  399. ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u, dma_half_buffer_min: %5u, dma_half_buffer: %5u,"
  400. "lines_per_half_buffer: %2u, dma_buffer_size: %5u, image_size: %u",
  401. (unsigned) (node_size * cam->dma_bytes_per_item), (unsigned) nodes_per_line, (unsigned) lines_per_node,
  402. (unsigned) (dma_half_buffer_min * cam->dma_bytes_per_item), (unsigned) (dma_half_buffer * cam->dma_bytes_per_item),
  403. (unsigned) (lines_per_half_buffer), (unsigned) (dma_buffer_size * cam->dma_bytes_per_item), (unsigned) image_size);
  404. cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
  405. cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item;
  406. cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item;
  407. cam->dma_half_buffer_cnt = cam->dma_buffer_size / cam->dma_half_buffer_size;
  408. return 1;
  409. }
  410. bool ll_cam_dma_sizes(cam_obj_t *cam)
  411. {
  412. cam->dma_bytes_per_item = ll_cam_bytes_per_sample(sampling_mode);
  413. if (cam->jpeg_mode) {
  414. cam->dma_half_buffer_cnt = 8;
  415. cam->dma_node_buffer_size = 2048;
  416. cam->dma_half_buffer_size = cam->dma_node_buffer_size * 2;
  417. cam->dma_buffer_size = cam->dma_half_buffer_cnt * cam->dma_half_buffer_size;
  418. } else {
  419. return ll_cam_calc_rgb_dma(cam);
  420. }
  421. return 1;
  422. }
  423. static dma_filter_t dma_filter = ll_cam_dma_filter_jpeg;
  424. size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len)
  425. {
  426. //DBG_PIN_SET(1);
  427. size_t r = dma_filter(out, in, len);
  428. //DBG_PIN_SET(0);
  429. return r;
  430. }
  431. esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid)
  432. {
  433. if (pix_format == PIXFORMAT_GRAYSCALE) {
  434. if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID || sensor_pid == SC031GS_PID || sensor_pid == BF20A6_PID || sensor_pid == GC0308_PID) {
  435. if (xclk_freq_hz > 10000000) {
  436. sampling_mode = SM_0A00_0B00;
  437. dma_filter = ll_cam_dma_filter_yuyv_highspeed;
  438. } else {
  439. sampling_mode = SM_0A0B_0C0D;
  440. dma_filter = ll_cam_dma_filter_yuyv;
  441. }
  442. cam->in_bytes_per_pixel = 1; // camera sends Y8
  443. } else {
  444. if (xclk_freq_hz > 10000000 && sensor_pid != OV7725_PID) {
  445. sampling_mode = SM_0A00_0B00;
  446. dma_filter = ll_cam_dma_filter_grayscale_highspeed;
  447. } else {
  448. sampling_mode = SM_0A0B_0C0D;
  449. dma_filter = ll_cam_dma_filter_grayscale;
  450. }
  451. cam->in_bytes_per_pixel = 2; // camera sends YU/YV
  452. }
  453. cam->fb_bytes_per_pixel = 1; // frame buffer stores Y8
  454. } else if (pix_format == PIXFORMAT_YUV422 || pix_format == PIXFORMAT_RGB565) {
  455. if (xclk_freq_hz > 10000000 && sensor_pid != OV7725_PID) {
  456. if (sensor_pid == OV7670_PID) {
  457. sampling_mode = SM_0A0B_0B0C;
  458. } else {
  459. sampling_mode = SM_0A00_0B00;
  460. }
  461. dma_filter = ll_cam_dma_filter_yuyv_highspeed;
  462. } else {
  463. sampling_mode = SM_0A0B_0C0D;
  464. dma_filter = ll_cam_dma_filter_yuyv;
  465. }
  466. cam->in_bytes_per_pixel = 2; // camera sends YU/YV
  467. cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
  468. } else if (pix_format == PIXFORMAT_JPEG) {
  469. cam->in_bytes_per_pixel = 1;
  470. cam->fb_bytes_per_pixel = 1;
  471. dma_filter = ll_cam_dma_filter_jpeg;
  472. sampling_mode = SM_0A00_0B00;
  473. } else {
  474. ESP_LOGE(TAG, "Requested format is not supported");
  475. return ESP_ERR_NOT_SUPPORTED;
  476. }
  477. I2S0.fifo_conf.rx_fifo_mod = sampling_mode;
  478. return ESP_OK;
  479. }