fsl_csi.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  1. /*
  2. * Copyright 2017-2021 NXP
  3. * All rights reserved.
  4. *
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_csi.h"
  9. #if CSI_DRIVER_FRAG_MODE
  10. #include "fsl_cache.h"
  11. #endif
  12. #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
  13. #include "fsl_memory.h"
  14. #endif
  15. /*******************************************************************************
  16. * Definitions
  17. ******************************************************************************/
  18. /* Macro remap. */
  19. #if (!defined(CSI_CR3_TWO_8BIT_SENSOR_MASK) && defined(CSI_CR3_SENSOR_16BITS_MASK))
  20. #define CSI_CR3_TWO_8BIT_SENSOR_MASK CSI_CR3_SENSOR_16BITS_MASK
  21. #endif
  22. /* Component ID definition, used by tools. */
  23. #ifndef FSL_COMPONENT_ID
  24. #define FSL_COMPONENT_ID "platform.drivers.csi"
  25. #endif
  26. /* Two frame buffer loaded to CSI register at most. */
  27. #define CSI_MAX_ACTIVE_FRAME_NUM 2U
  28. /* CSI driver only support RGB565 and YUV422 in fragment mode, 2 bytes per pixel. */
  29. #define CSI_FRAG_INPUT_BYTES_PER_PIXEL 2U
  30. #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
  31. #define CSI_ADDR_CPU_2_IP(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_Local2DMA))
  32. #define CSI_ADDR_IP_2_CPU(addr) (MEMORY_ConvertMemoryMapAddress((uint32_t)(addr), kMEMORY_DMA2Local))
  33. #else
  34. #define CSI_ADDR_CPU_2_IP(addr) (addr)
  35. #define CSI_ADDR_IP_2_CPU(addr) (addr)
  36. #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
  37. /*!
  38. * @brief Used for conversion between `void*` and `uint32_t`.
  39. */
  40. typedef union pvoid_to_u32
  41. {
  42. void *pvoid;
  43. uint32_t u32;
  44. } pvoid_to_u32_t;
  45. /*******************************************************************************
  46. * Prototypes
  47. ******************************************************************************/
  48. /*!
  49. * @brief Get the instance from the base address
  50. *
  51. * @param base CSI peripheral base address
  52. *
  53. * @return The CSI module instance
  54. */
  55. static uint32_t CSI_GetInstance(CSI_Type *base);
  56. #if !CSI_DRIVER_FRAG_MODE
  57. /*!
  58. * @brief Get the delta value of two index in queue.
  59. *
  60. * @param startIdx Start index.
  61. * @param endIdx End index.
  62. *
  63. * @return The delta between startIdx and endIdx in queue.
  64. */
  65. static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx);
  66. /*!
  67. * @brief Increase a index value in queue.
  68. *
  69. * This function increases the index value in the queue, if the index is out of
  70. * the queue range, it is reset to 0.
  71. *
  72. * @param idx The index value to increase.
  73. *
  74. * @return The index value after increase.
  75. */
  76. static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx);
  77. /*!
  78. * @brief Get the empty frame buffer count in queue.
  79. *
  80. * @param base CSI peripheral base address
  81. * @param handle Pointer to CSI driver handle.
  82. *
  83. * @return Number of the empty frame buffer count in queue.
  84. */
  85. static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle);
  86. /*!
  87. * @brief Get the empty frame buffer.
  88. *
  89. * This function should only be called when frame buffer count larger than 0.
  90. *
  91. * @param handle Pointer to CSI driver handle.
  92. *
  93. * @return Empty buffer
  94. */
  95. static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle);
  96. /*!
  97. * @brief Put the empty frame buffer.
  98. *
  99. * @param handle Pointer to CSI driver handle.
  100. * @param buffer The empty buffer to put.
  101. */
  102. static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer);
  103. /*!
  104. * @brief Get the RX frame buffer address.
  105. *
  106. * @param base CSI peripheral base address.
  107. * @param index Buffer index.
  108. * @return Frame buffer address.
  109. */
  110. static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index);
  111. /* Typedef for interrupt handler. */
  112. typedef void (*csi_isr_t)(CSI_Type *base, csi_handle_t *handle);
  113. #else
  114. /* Typedef for interrupt handler to work in fragment mode. */
  115. typedef void (*csi_isr_t)(CSI_Type *base, csi_frag_handle_t *handle);
  116. #endif /* CSI_DRIVER_FRAG_MODE */
  117. /*******************************************************************************
  118. * Variables
  119. ******************************************************************************/
  120. /*! @brief Pointers to CSI bases for each instance. */
  121. static CSI_Type *const s_csiBases[] = CSI_BASE_PTRS;
  122. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  123. /*! @brief Pointers to CSI clocks for each CSI submodule. */
  124. static const clock_ip_name_t s_csiClocks[] = CSI_CLOCKS;
  125. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  126. /* Array for the CSI driver handle. */
  127. #if !CSI_DRIVER_FRAG_MODE
  128. static csi_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
  129. #else
  130. static csi_frag_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
  131. #endif
  132. /* Array of CSI IRQ number. */
  133. static const IRQn_Type s_csiIRQ[] = CSI_IRQS;
  134. /* CSI ISR for transactional APIs. */
  135. #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
  136. static csi_isr_t s_csiIsr = (csi_isr_t)DefaultISR;
  137. #else
  138. static csi_isr_t s_csiIsr;
  139. #endif
  140. /*******************************************************************************
  141. * Code
  142. ******************************************************************************/
  143. static uint32_t CSI_GetInstance(CSI_Type *base)
  144. {
  145. uint32_t instance;
  146. /* Find the instance index from base address mappings. */
  147. for (instance = 0; instance < ARRAY_SIZE(s_csiBases); instance++)
  148. {
  149. if (s_csiBases[instance] == base)
  150. {
  151. break;
  152. }
  153. }
  154. assert(instance < ARRAY_SIZE(s_csiBases));
  155. return instance;
  156. }
  157. #if !CSI_DRIVER_FRAG_MODE
  158. static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx)
  159. {
  160. uint8_t ret;
  161. if (endIdx >= startIdx)
  162. {
  163. ret = endIdx - startIdx;
  164. }
  165. else
  166. {
  167. ret = (uint8_t)(endIdx + CSI_DRIVER_ACTUAL_QUEUE_SIZE - startIdx);
  168. }
  169. return ret;
  170. }
  171. static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx)
  172. {
  173. uint8_t ret;
  174. /*
  175. * Here not use the method:
  176. * ret = (idx+1) % CSI_DRIVER_ACTUAL_QUEUE_SIZE;
  177. *
  178. * Because the mod function might be slow.
  179. */
  180. ret = idx + 1U;
  181. if (ret >= CSI_DRIVER_ACTUAL_QUEUE_SIZE)
  182. {
  183. ret = 0U;
  184. }
  185. return ret;
  186. }
  187. static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle)
  188. {
  189. return handle->emptyBufferCnt;
  190. }
  191. static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle)
  192. {
  193. pvoid_to_u32_t buf;
  194. buf.pvoid = handle->emptyBuffer;
  195. handle->emptyBufferCnt--;
  196. handle->emptyBuffer = *(void **)(buf.pvoid);
  197. return buf.u32;
  198. }
  199. static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer)
  200. {
  201. pvoid_to_u32_t buf;
  202. buf.u32 = buffer;
  203. *(void **)(buf.pvoid) = handle->emptyBuffer;
  204. handle->emptyBuffer = buf.pvoid;
  205. handle->emptyBufferCnt++;
  206. }
  207. static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index)
  208. {
  209. uint32_t addr;
  210. if (index != 0U)
  211. {
  212. addr = CSI_REG_DMASA_FB2(base);
  213. }
  214. else
  215. {
  216. addr = CSI_REG_DMASA_FB1(base);
  217. }
  218. return CSI_ADDR_IP_2_CPU(addr);
  219. }
  220. #endif /* CSI_DRIVER_FRAG_MODE */
  221. /*!
  222. * brief Initialize the CSI.
  223. *
  224. * This function enables the CSI peripheral clock, and resets the CSI registers.
  225. *
  226. * param base CSI peripheral base address.
  227. * param config Pointer to the configuration structure.
  228. *
  229. * retval kStatus_Success Initialize successfully.
  230. * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
  231. */
  232. status_t CSI_Init(CSI_Type *base, const csi_config_t *config)
  233. {
  234. assert(NULL != config);
  235. uint32_t reg;
  236. uint32_t imgWidth_Bytes;
  237. uint8_t busCyclePerPixel;
  238. imgWidth_Bytes = (uint32_t)config->width * (uint32_t)config->bytesPerPixel;
  239. /* The image width and frame buffer pitch should be multiple of 8-bytes. */
  240. if ((0U != (imgWidth_Bytes & 0x07U)) || (0U != ((uint32_t)config->linePitch_Bytes & 0x07U)))
  241. {
  242. return kStatus_InvalidArgument;
  243. }
  244. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  245. uint32_t instance = CSI_GetInstance(base);
  246. CLOCK_EnableClock(s_csiClocks[instance]);
  247. #endif
  248. CSI_Reset(base);
  249. /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
  250. reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CR1_FCC_MASK;
  251. if (config->useExtVsync)
  252. {
  253. reg |= CSI_CR1_EXT_VSYNC_MASK;
  254. }
  255. CSI_REG_CR1(base) = reg;
  256. /*
  257. * Generally, CSIIMAG_PARA[IMAGE_WIDTH] indicates how many data bus cycles per line.
  258. * One special case is when receiving 24-bit pixels through 8-bit data bus.
  259. * In this case, the CSIIMAG_PARA[IMAGE_WIDTH] should be set to the pixel number per line.
  260. */
  261. if ((kCSI_DataBus8Bit == config->dataBus) && (2U == config->bytesPerPixel))
  262. {
  263. busCyclePerPixel = 2U;
  264. }
  265. else
  266. {
  267. busCyclePerPixel = 1U;
  268. }
  269. if (4U == config->bytesPerPixel)
  270. {
  271. CSI_REG_CR18(base) |= CSI_CR18_PARALLEL24_EN_MASK;
  272. }
  273. if (kCSI_DataBus16Bit == config->dataBus)
  274. {
  275. CSI_REG_CR3(base) |= CSI_CR3_TWO_8BIT_SENSOR_MASK;
  276. }
  277. /* Image parameter. */
  278. CSI_REG_IMAG_PARA(base) =
  279. (((uint32_t)config->width * (uint32_t)busCyclePerPixel) << CSI_IMAG_PARA_IMAGE_WIDTH_SHIFT) |
  280. ((uint32_t)(config->height) << CSI_IMAG_PARA_IMAGE_HEIGHT_SHIFT);
  281. /* The CSI frame buffer bus is 8-byte width. */
  282. CSI_REG_FBUF_PARA(base) = (uint32_t)((config->linePitch_Bytes - imgWidth_Bytes) / 8U)
  283. << CSI_FBUF_PARA_FBUF_STRIDE_SHIFT;
  284. /* Enable auto ECC. */
  285. CSI_REG_CR3(base) |= CSI_CR3_ECC_AUTO_EN_MASK;
  286. /*
  287. * For better performance.
  288. * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
  289. * choose the best burst size based on bytes per line.
  290. */
  291. if (0U == (imgWidth_Bytes % (8U * 16U)))
  292. {
  293. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(3U);
  294. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((2U << CSI_CR3_RxFF_LEVEL_SHIFT));
  295. }
  296. else if (0U == (imgWidth_Bytes % (8U * 8U)))
  297. {
  298. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(2U);
  299. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((1U << CSI_CR3_RxFF_LEVEL_SHIFT));
  300. }
  301. else
  302. {
  303. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(1U);
  304. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((0U << CSI_CR3_RxFF_LEVEL_SHIFT));
  305. }
  306. CSI_ReflashFifoDma(base, kCSI_RxFifo);
  307. return kStatus_Success;
  308. }
  309. /*!
  310. * brief De-initialize the CSI.
  311. *
  312. * This function disables the CSI peripheral clock.
  313. *
  314. * param base CSI peripheral base address.
  315. */
  316. void CSI_Deinit(CSI_Type *base)
  317. {
  318. /* Disable transfer first. */
  319. CSI_Stop(base);
  320. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  321. uint32_t instance = CSI_GetInstance(base);
  322. CLOCK_DisableClock(s_csiClocks[instance]);
  323. #endif
  324. }
  325. /*!
  326. * brief Reset the CSI.
  327. *
  328. * This function resets the CSI peripheral registers to default status.
  329. *
  330. * param base CSI peripheral base address.
  331. */
  332. void CSI_Reset(CSI_Type *base)
  333. {
  334. uint32_t csisr;
  335. /* Disable transfer first. */
  336. CSI_Stop(base);
  337. /* Disable DMA request. */
  338. CSI_REG_CR3(base) = 0U;
  339. /* Reset the fame count. */
  340. CSI_REG_CR3(base) |= CSI_CR3_FRMCNT_RST_MASK;
  341. while (0U != (CSI_REG_CR3(base) & CSI_CR3_FRMCNT_RST_MASK))
  342. {
  343. }
  344. /* Clear the RX FIFO. */
  345. CSI_ClearFifo(base, kCSI_AllFifo);
  346. /* Reflash DMA. */
  347. CSI_ReflashFifoDma(base, kCSI_AllFifo);
  348. /* Clear the status. */
  349. csisr = CSI_REG_SR(base);
  350. CSI_REG_SR(base) = csisr;
  351. /* Set the control registers to default value. */
  352. CSI_REG_CR1(base) = CSI_CR1_HSYNC_POL_MASK | CSI_CR1_EXT_VSYNC_MASK;
  353. CSI_REG_CR2(base) = 0U;
  354. CSI_REG_CR3(base) = 0U;
  355. #if defined(CSI_CR18_CSI_LCDIF_BUFFER_LINES)
  356. CSI_REG_CR18(base) = CSI_CR18_AHB_HPROT(0x0DU) | CSI_CR18_CSI_LCDIF_BUFFER_LINES(0x02U);
  357. #else
  358. CSI_REG_CR18(base) = CSI_CR18_AHB_HPROT(0x0DU);
  359. #endif
  360. CSI_REG_FBUF_PARA(base) = 0U;
  361. CSI_REG_IMAG_PARA(base) = 0U;
  362. }
  363. /*!
  364. * brief Get the default configuration for to initialize the CSI.
  365. *
  366. * The default configuration value is:
  367. *
  368. * code
  369. config->width = 320U;
  370. config->height = 240U;
  371. config->polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge;
  372. config->bytesPerPixel = 2U;
  373. config->linePitch_Bytes = 320U * 2U;
  374. config->workMode = kCSI_GatedClockMode;
  375. config->dataBus = kCSI_DataBus8Bit;
  376. config->useExtVsync = true;
  377. endcode
  378. *
  379. * param config Pointer to the CSI configuration.
  380. */
  381. void CSI_GetDefaultConfig(csi_config_t *config)
  382. {
  383. assert(NULL != config);
  384. /* Initializes the configure structure to zero. */
  385. (void)memset(config, 0, sizeof(*config));
  386. config->width = 320U;
  387. config->height = 240U;
  388. config->polarityFlags = (uint32_t)kCSI_HsyncActiveHigh | (uint32_t)kCSI_DataLatchOnRisingEdge;
  389. config->bytesPerPixel = 2U;
  390. config->linePitch_Bytes = 320U * 2U;
  391. config->workMode = kCSI_GatedClockMode;
  392. config->dataBus = kCSI_DataBus8Bit;
  393. config->useExtVsync = true;
  394. }
  395. /*!
  396. * brief Set the RX frame buffer address.
  397. *
  398. * param base CSI peripheral base address.
  399. * param index Buffer index.
  400. * param addr Frame buffer address to set.
  401. */
  402. void CSI_SetRxBufferAddr(CSI_Type *base, uint8_t index, uint32_t addr)
  403. {
  404. addr = CSI_ADDR_CPU_2_IP(addr);
  405. if (0U != index)
  406. {
  407. CSI_REG_DMASA_FB2(base) = addr;
  408. }
  409. else
  410. {
  411. CSI_REG_DMASA_FB1(base) = addr;
  412. }
  413. }
  414. /*!
  415. * brief Clear the CSI FIFO.
  416. *
  417. * This function clears the CSI FIFO.
  418. *
  419. * param base CSI peripheral base address.
  420. * param fifo The FIFO to clear.
  421. */
  422. void CSI_ClearFifo(CSI_Type *base, csi_fifo_t fifo)
  423. {
  424. uint32_t cr1;
  425. uint32_t mask = 0U;
  426. /* The FIFO could only be cleared when CSICR1[FCC] = 0, so first clear the FCC. */
  427. cr1 = CSI_REG_CR1(base);
  428. CSI_REG_CR1(base) = (cr1 & ~CSI_CR1_FCC_MASK);
  429. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
  430. {
  431. mask |= CSI_CR1_CLR_RXFIFO_MASK;
  432. }
  433. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
  434. {
  435. mask |= CSI_CR1_CLR_STATFIFO_MASK;
  436. }
  437. CSI_REG_CR1(base) = (cr1 & ~CSI_CR1_FCC_MASK) | mask;
  438. /* Wait clear completed. */
  439. while (0U != (CSI_REG_CR1(base) & mask))
  440. {
  441. }
  442. /* Recover the FCC. */
  443. CSI_REG_CR1(base) = cr1;
  444. }
  445. /*!
  446. * brief Reflash the CSI FIFO DMA.
  447. *
  448. * This function reflashes the CSI FIFO DMA.
  449. *
  450. * For RXFIFO, there are two frame buffers. When the CSI module started, it saves
  451. * the frames to frame buffer 0 then frame buffer 1, the two buffers will be
  452. * written by turns. After reflash DMA using this function, the CSI is reset to
  453. * save frame to buffer 0.
  454. *
  455. * param base CSI peripheral base address.
  456. * param fifo The FIFO DMA to reflash.
  457. */
  458. void CSI_ReflashFifoDma(CSI_Type *base, csi_fifo_t fifo)
  459. {
  460. uint32_t cr3 = 0U;
  461. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
  462. {
  463. cr3 |= CSI_CR3_DMA_REFLASH_RFF_MASK;
  464. }
  465. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
  466. {
  467. cr3 |= CSI_CR3_DMA_REFLASH_SFF_MASK;
  468. }
  469. CSI_REG_CR3(base) |= cr3;
  470. /* Wait clear completed. */
  471. while (0U != (CSI_REG_CR3(base) & cr3))
  472. {
  473. }
  474. }
  475. /*!
  476. * brief Enable or disable the CSI FIFO DMA request.
  477. *
  478. * param base CSI peripheral base address.
  479. * param fifo The FIFO DMA reques to enable or disable.
  480. * param enable True to enable, false to disable.
  481. */
  482. void CSI_EnableFifoDmaRequest(CSI_Type *base, csi_fifo_t fifo, bool enable)
  483. {
  484. uint32_t cr3 = 0U;
  485. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
  486. {
  487. cr3 |= CSI_CR3_DMA_REQ_EN_RFF_MASK;
  488. }
  489. if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
  490. {
  491. cr3 |= CSI_CR3_DMA_REQ_EN_SFF_MASK;
  492. }
  493. if (enable)
  494. {
  495. CSI_REG_CR3(base) |= cr3;
  496. }
  497. else
  498. {
  499. CSI_REG_CR3(base) &= ~cr3;
  500. }
  501. }
  502. /*!
  503. * brief Enables CSI interrupt requests.
  504. *
  505. * param base CSI peripheral base address.
  506. * param mask The interrupts to enable, pass in as OR'ed value of ref _csi_interrupt_enable.
  507. */
  508. void CSI_EnableInterrupts(CSI_Type *base, uint32_t mask)
  509. {
  510. CSI_REG_CR1(base) |= (mask & CSI_CR1_INT_EN_MASK);
  511. CSI_REG_CR3(base) |= (mask & CSI_CR3_INT_EN_MASK);
  512. CSI_REG_CR18(base) |= ((mask & CSI_CR18_INT_EN_MASK) >> 6U);
  513. }
  514. /*!
  515. * brief Disable CSI interrupt requests.
  516. *
  517. * param base CSI peripheral base address.
  518. * param mask The interrupts to disable, pass in as OR'ed value of ref _csi_interrupt_enable.
  519. */
  520. void CSI_DisableInterrupts(CSI_Type *base, uint32_t mask)
  521. {
  522. CSI_REG_CR1(base) &= ~(mask & CSI_CR1_INT_EN_MASK);
  523. CSI_REG_CR3(base) &= ~(mask & CSI_CR3_INT_EN_MASK);
  524. CSI_REG_CR18(base) &= ~((mask & CSI_CR18_INT_EN_MASK) >> 6U);
  525. }
  526. #if !CSI_DRIVER_FRAG_MODE
  527. /*!
  528. * brief Initializes the CSI handle.
  529. *
  530. * This function initializes CSI handle, it should be called before any other
  531. * CSI transactional functions.
  532. *
  533. * param base CSI peripheral base address.
  534. * param handle Pointer to the handle structure.
  535. * param callback Callback function for CSI transfer.
  536. * param userData Callback function parameter.
  537. *
  538. * retval kStatus_Success Handle created successfully.
  539. */
  540. status_t CSI_TransferCreateHandle(CSI_Type *base,
  541. csi_handle_t *handle,
  542. csi_transfer_callback_t callback,
  543. void *userData)
  544. {
  545. assert(NULL != handle);
  546. uint32_t instance;
  547. (void)memset(handle, 0, sizeof(*handle));
  548. /* Set the callback and user data. */
  549. handle->callback = callback;
  550. handle->userData = userData;
  551. /* Get instance from peripheral base address. */
  552. instance = CSI_GetInstance(base);
  553. /* Save the handle in global variables to support the double weak mechanism. */
  554. s_csiHandle[instance] = handle;
  555. s_csiIsr = CSI_TransferHandleIRQ;
  556. /* Enable interrupt. */
  557. (void)EnableIRQ(s_csiIRQ[instance]);
  558. return kStatus_Success;
  559. }
  560. /*!
  561. * brief Start the transfer using transactional functions.
  562. *
  563. * When the empty frame buffers have been submit to CSI driver using function
  564. * ref CSI_TransferSubmitEmptyBuffer, user could call this function to start
  565. * the transfer. The incoming frame will be saved to the empty frame buffer,
  566. * and user could be optionally notified through callback function.
  567. *
  568. * param base CSI peripheral base address.
  569. * param handle Pointer to the handle structure.
  570. *
  571. * retval kStatus_Success Started successfully.
  572. * retval kStatus_CSI_NoEmptyBuffer Could not start because no empty frame buffer in queue.
  573. */
  574. status_t CSI_TransferStart(CSI_Type *base, csi_handle_t *handle)
  575. {
  576. assert(NULL != handle);
  577. uint32_t emptyBufferCount;
  578. emptyBufferCount = CSI_TransferGetEmptyBufferCount(handle);
  579. if (emptyBufferCount < 2U)
  580. {
  581. return kStatus_CSI_NoEmptyBuffer;
  582. }
  583. /*
  584. * Write to memory from first completed frame.
  585. * DMA base addr switch at the edge of the first data of each frame, thus
  586. * if one frame is broken, it could be reset at the next frame.
  587. */
  588. CSI_REG_CR18(base) = (CSI_REG_CR18(base) & ~CSI_CR18_MASK_OPTION_MASK) | CSI_CR18_MASK_OPTION(0) |
  589. CSI_CR18_BASEADDR_SWITCH_SEL_MASK | CSI_CR18_BASEADDR_SWITCH_EN_MASK;
  590. /* Load the frame buffer to CSI register, there are at least two empty buffers. */
  591. CSI_REG_DMASA_FB1(base) = CSI_ADDR_CPU_2_IP(CSI_TransferGetEmptyBuffer(handle));
  592. CSI_REG_DMASA_FB2(base) = CSI_ADDR_CPU_2_IP(CSI_TransferGetEmptyBuffer(handle));
  593. handle->activeBufferNum = CSI_MAX_ACTIVE_FRAME_NUM;
  594. /* After reflash DMA, the CSI saves frame to frame buffer 0. */
  595. CSI_ReflashFifoDma(base, kCSI_RxFifo);
  596. handle->transferStarted = true;
  597. CSI_EnableInterrupts(
  598. base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
  599. CSI_Start(base);
  600. return kStatus_Success;
  601. }
  602. /*!
  603. * brief Stop the transfer using transactional functions.
  604. *
  605. * The driver does not clean the full frame buffers in queue. In other words, after
  606. * calling this function, user still could get the full frame buffers in queue
  607. * using function ref CSI_TransferGetFullBuffer.
  608. *
  609. * param base CSI peripheral base address.
  610. * param handle Pointer to the handle structure.
  611. *
  612. * retval kStatus_Success Stoped successfully.
  613. */
  614. status_t CSI_TransferStop(CSI_Type *base, csi_handle_t *handle)
  615. {
  616. assert(NULL != handle);
  617. uint8_t activeBufferNum;
  618. uint8_t bufIdx;
  619. CSI_Stop(base);
  620. CSI_DisableInterrupts(
  621. base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
  622. activeBufferNum = handle->activeBufferNum;
  623. handle->transferStarted = false;
  624. handle->activeBufferNum = 0;
  625. /*
  626. * Put active buffers to empty queue.
  627. *
  628. * If there is only one active frame buffers, then FB0 and FB1 use the same address,
  629. * put FB0 to empty buffer queue is OK.
  630. */
  631. for (bufIdx = 0; bufIdx < activeBufferNum; bufIdx++)
  632. {
  633. CSI_TransferPutEmptyBuffer(handle, CSI_GetRxBufferAddr(base, bufIdx));
  634. }
  635. return kStatus_Success;
  636. }
  637. /*!
  638. * brief Submit empty frame buffer to queue.
  639. *
  640. * This function could be called before ref CSI_TransferStart or after ref
  641. * CSI_TransferStart. If there is no room in queue to store the empty frame
  642. * buffer, this function returns error.
  643. *
  644. * param base CSI peripheral base address.
  645. * param handle Pointer to the handle structure.
  646. * param frameBuffer Empty frame buffer to submit.
  647. *
  648. * retval kStatus_Success Started successfully.
  649. * retval kStatus_CSI_QueueFull Could not submit because there is no room in queue.
  650. */
  651. status_t CSI_TransferSubmitEmptyBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t frameBuffer)
  652. {
  653. uint32_t csicr1;
  654. /* Disable the interrupt to protect the index information in handle. */
  655. csicr1 = CSI_REG_CR1(base);
  656. CSI_REG_CR1(base) = (csicr1 & ~(CSI_CR1_FB2_DMA_DONE_INTEN_MASK | CSI_CR1_FB1_DMA_DONE_INTEN_MASK));
  657. /* Save the empty frame buffer address to queue. */
  658. CSI_TransferPutEmptyBuffer(handle, frameBuffer);
  659. CSI_REG_CR1(base) = csicr1;
  660. return kStatus_Success;
  661. }
  662. /*!
  663. * brief Get one full frame buffer from queue.
  664. *
  665. * After the transfer started using function ref CSI_TransferStart, the incoming
  666. * frames will be saved to the empty frame buffers in queue. This function gets
  667. * the full-filled frame buffer from the queue. If there is no full frame buffer
  668. * in queue, this function returns error.
  669. *
  670. * param base CSI peripheral base address.
  671. * param handle Pointer to the handle structure.
  672. * param frameBuffer Full frame buffer.
  673. *
  674. * retval kStatus_Success Started successfully.
  675. * retval kStatus_CSI_NoFullBuffer There is no full frame buffer in queue.
  676. */
  677. status_t CSI_TransferGetFullBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t *frameBuffer)
  678. {
  679. uint32_t csicr1;
  680. status_t status;
  681. uint8_t queueReadIdx;
  682. uint8_t queueWriteIdx;
  683. queueReadIdx = handle->queueReadIdx;
  684. queueWriteIdx = handle->queueWriteIdx;
  685. /* No full frame buffer. */
  686. if (queueReadIdx == queueWriteIdx)
  687. {
  688. status = kStatus_CSI_NoFullBuffer;
  689. }
  690. else
  691. {
  692. /* Disable the interrupt to protect the index information in handle. */
  693. csicr1 = CSI_REG_CR1(base);
  694. CSI_REG_CR1(base) = (csicr1 & ~(CSI_CR1_FB2_DMA_DONE_INTEN_MASK | CSI_CR1_FB1_DMA_DONE_INTEN_MASK));
  695. *frameBuffer = handle->frameBufferQueue[handle->queueReadIdx];
  696. handle->queueReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueReadIdx);
  697. CSI_REG_CR1(base) = csicr1;
  698. status = kStatus_Success;
  699. }
  700. return status;
  701. }
  702. /*!
  703. * brief CSI IRQ handle function.
  704. *
  705. * This function handles the CSI IRQ request to work with CSI driver transactional
  706. * APIs.
  707. *
  708. * param base CSI peripheral base address.
  709. * param handle CSI handle pointer.
  710. */
  711. void CSI_TransferHandleIRQ(CSI_Type *base, csi_handle_t *handle)
  712. {
  713. uint8_t queueWriteIdx;
  714. uint8_t queueReadIdx;
  715. uint8_t dmaDoneBufferIdx;
  716. uint32_t frameBuffer;
  717. uint32_t csisr = CSI_REG_SR(base);
  718. /* Clear the error flags. */
  719. CSI_REG_SR(base) = csisr;
  720. /*
  721. * If both frame buffer 0 and frame buffer 1 flags assert, driver does not
  722. * know which frame buffer ready just now, so skip them.
  723. */
  724. if ((csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)) ==
  725. (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK))
  726. {
  727. ; /* Skip the frames. */
  728. }
  729. else if (0U != (csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)))
  730. {
  731. if (0U != (csisr & CSI_SR_DMA_TSF_DONE_FB2_MASK))
  732. {
  733. dmaDoneBufferIdx = 1;
  734. }
  735. else
  736. {
  737. dmaDoneBufferIdx = 0;
  738. }
  739. if (handle->activeBufferNum == CSI_MAX_ACTIVE_FRAME_NUM)
  740. {
  741. queueWriteIdx = handle->queueWriteIdx;
  742. queueReadIdx = handle->queueReadIdx;
  743. if (CSI_TransferGetQueueDelta(queueReadIdx, queueWriteIdx) < CSI_DRIVER_QUEUE_SIZE)
  744. {
  745. /* Put the full frame buffer to full buffer queue. */
  746. frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx);
  747. handle->frameBufferQueue[queueWriteIdx] = frameBuffer;
  748. handle->queueWriteIdx = CSI_TransferIncreaseQueueIdx(queueWriteIdx);
  749. handle->activeBufferNum--;
  750. if (NULL != handle->callback)
  751. {
  752. handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
  753. }
  754. }
  755. else
  756. {
  757. }
  758. }
  759. /*
  760. * User may submit new frame buffer in callback, so recheck activeBufferNum here,
  761. * if there is only one active buffer in CSI device, the two buffer registers
  762. * are both set to the frame buffer address.
  763. */
  764. if (handle->activeBufferNum < CSI_MAX_ACTIVE_FRAME_NUM)
  765. {
  766. if (CSI_TransferGetEmptyBufferCount(handle) > 0U)
  767. {
  768. /* Get the empty frameBuffer, and submit to CSI device. */
  769. CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, CSI_TransferGetEmptyBuffer(handle));
  770. handle->activeBufferNum++;
  771. }
  772. else
  773. {
  774. /* If there is only one active frame buffer, then the two CSI
  775. * output buffer address are all set to this frame buffer.
  776. */
  777. frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx ^ 1U);
  778. CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, frameBuffer);
  779. }
  780. }
  781. }
  782. else
  783. {
  784. }
  785. }
  786. #else /* CSI_DRIVER_FRAG_MODE */
  787. #if defined(__CC_ARM)
  788. __asm void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
  789. {
  790. /* clang-format off */
  791. push {r4-r7, lr}
  792. 10
  793. LDMIA R1!, {r3-r6}
  794. bfi r7, r3, #0, #8 /* Y0 */
  795. bfi ip, r5, #0, #8 /* Y4 */
  796. lsr r3, r3, #16
  797. lsr r5, r5, #16
  798. bfi r7, r3, #8, #8 /* Y1 */
  799. bfi ip, r5, #8, #8 /* Y5 */
  800. bfi r7, r4, #16, #8 /* Y2 */
  801. bfi ip, r6, #16, #8 /* Y6 */
  802. lsr r4, r4, #16
  803. lsr r6, r6, #16
  804. bfi r7, r4, #24, #8 /* Y3 */
  805. bfi ip, r6, #24, #8 /* Y7 */
  806. STMIA r0!, {r7, ip}
  807. subs r2, #8
  808. bne %b10
  809. pop {r4-r7, pc}
  810. /* clang-format on */
  811. }
  812. __asm void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
  813. {
  814. /* clang-format off */
  815. push {r4-r7, lr}
  816. 10
  817. LDMIA R1!, {r3-r6}
  818. lsr r3, r3, #8
  819. lsr r5, r5, #8
  820. bfi r7, r3, #0, #8 /* Y0 */
  821. bfi ip, r5, #0, #8 /* Y4 */
  822. lsr r3, r3, #16
  823. lsr r5, r5, #16
  824. bfi r7, r3, #8, #8 /* Y1 */
  825. bfi ip, r5, #8, #8 /* Y5 */
  826. lsr r4, r4, #8
  827. lsr r6, r6, #8
  828. bfi r7, r4, #16, #8 /* Y2 */
  829. bfi ip, r6, #16, #8 /* Y6 */
  830. lsr r4, r4, #16
  831. lsr r6, r6, #16
  832. bfi r7, r4, #24, #8 /* Y3 */
  833. bfi ip, r6, #24, #8 /* Y7 */
  834. STMIA r0!, {r7, ip}
  835. subs r2, #8
  836. bne %b10
  837. pop {r4-r7, pc}
  838. /* clang-format on */
  839. }
  840. #elif (defined(__GNUC__) || defined(__ICCARM__)) || defined(__ARMCC_VERSION)
  841. #if defined(__ICCARM__)
  842. #pragma diag_suppress = Pe940
  843. #endif
  844. __attribute__((naked)) void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count);
  845. void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
  846. {
  847. /* clang-format off */
  848. __asm volatile(
  849. " push {r1-r7, r12, lr} \n"
  850. "loop0: \n"
  851. " ldmia r1!, {r3-r6} \n"
  852. " bfi r7, r3, #0, #8 \n" /* Y0 */
  853. " bfi r12, r5, #0, #8 \n" /* Y4 */
  854. " lsr r3, r3, #16 \n"
  855. " lsr r5, r5, #16 \n"
  856. " bfi r7, r3, #8, #8 \n" /* Y1 */
  857. " bfi r12, r5, #8, #8 \n" /* Y5 */
  858. " bfi r7, r4, #16, #8 \n" /* Y2 */
  859. " bfi r12, r6, #16, #8 \n" /* Y6 */
  860. " lsr r4, r4, #16 \n"
  861. " lsr r6, r6, #16 \n"
  862. " bfi r7, r4, #24, #8 \n" /* Y3 */
  863. " bfi r12, r6, #24, #8 \n" /* Y7 */
  864. " stmia r0!, {r7, r12} \n"
  865. " subs r2, #8 \n"
  866. " bne loop0 \n"
  867. " pop {r1-r7, r12, pc} \n");
  868. /* clang-format on */
  869. }
  870. __attribute__((naked)) void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count);
  871. void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
  872. {
  873. /* clang-format off */
  874. __asm volatile(
  875. " push {r1-r7, r12, lr} \n"
  876. "loop1: \n"
  877. " ldmia r1!, {r3-r6} \n"
  878. " lsr r3, r3, #8 \n"
  879. " lsr r5, r5, #8 \n"
  880. " bfi r7, r3, #0, #8 \n" /* Y0 */
  881. " bfi r12, r5, #0, #8 \n" /* Y4 */
  882. " lsr r3, r3, #16 \n"
  883. " lsr r5, r5, #16 \n"
  884. " bfi r7, r3, #8, #8 \n" /* Y1 */
  885. " bfi r12, r5, #8, #8 \n" /* Y5 */
  886. " lsr r4, r4, #8 \n"
  887. " lsr r6, r6, #8 \n"
  888. " bfi r7, r4, #16, #8 \n" /* Y2 */
  889. " bfi r12, r6, #16, #8 \n" /* Y6 */
  890. " lsr r4, r4, #16 \n"
  891. " lsr r6, r6, #16 \n"
  892. " bfi r7, r4, #24, #8 \n" /* Y3 */
  893. " bfi r12, r6, #24, #8 \n" /* Y7 */
  894. " stmia r0!, {r7, r12} \n"
  895. " subs r2, #8 \n"
  896. " bne loop1 \n"
  897. " pop {r1-r7, r12, pc} \n");
  898. /* clang-format on */
  899. }
  900. #if defined(__ICCARM__)
  901. #pragma diag_default = Pe940
  902. #endif
  903. #else
  904. #error Toolchain not supported.
  905. #endif
  906. static void CSI_MemCopy(void *pDest, const void *pSrc, size_t cnt)
  907. {
  908. (void)memcpy(pDest, pSrc, cnt);
  909. }
  910. /*!
  911. * brief Initialize the CSI to work in fragment mode.
  912. *
  913. * This function enables the CSI peripheral clock, and resets the CSI registers.
  914. *
  915. * param base CSI peripheral base address.
  916. */
  917. void CSI_FragModeInit(CSI_Type *base)
  918. {
  919. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  920. uint32_t instance = CSI_GetInstance(base);
  921. CLOCK_EnableClock(s_csiClocks[instance]);
  922. #endif
  923. CSI_Reset(base);
  924. }
  925. /*!
  926. * brief De-initialize the CSI.
  927. *
  928. * This function disables the CSI peripheral clock.
  929. *
  930. * param base CSI peripheral base address.
  931. */
  932. void CSI_FragModeDeinit(CSI_Type *base)
  933. {
  934. CSI_Deinit(base);
  935. }
  936. /*!
  937. * brief Create handle for CSI work in fragment mode.
  938. *
  939. * param base CSI peripheral base address.
  940. * param handle Pointer to the transactional handle.
  941. * param config Pointer to the configuration structure.
  942. * param callback Callback function for CSI transfer.
  943. * param userData Callback function parameter.
  944. *
  945. * retval kStatus_Success Initialize successfully.
  946. * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
  947. */
  948. status_t CSI_FragModeCreateHandle(CSI_Type *base,
  949. csi_frag_handle_t *handle,
  950. const csi_frag_config_t *config,
  951. csi_frag_transfer_callback_t callback,
  952. void *userData)
  953. {
  954. assert(NULL != config);
  955. uint32_t reg;
  956. uint32_t instance;
  957. uint32_t imgWidth_Bytes;
  958. if (config->dataBus != kCSI_DataBus8Bit)
  959. {
  960. return kStatus_InvalidArgument;
  961. }
  962. imgWidth_Bytes = (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
  963. /* The image buffer line width should be multiple of 8-bytes. */
  964. if ((imgWidth_Bytes & 0x07U) != 0U)
  965. {
  966. return kStatus_InvalidArgument;
  967. }
  968. /* Camera frame height must be dividable by DMA buffer line. */
  969. if (config->height % config->dmaBufferLine != 0U)
  970. {
  971. return kStatus_InvalidArgument;
  972. }
  973. (void)memset(handle, 0, sizeof(*handle));
  974. handle->callback = callback;
  975. handle->userData = userData;
  976. handle->height = config->height;
  977. handle->width = config->width;
  978. handle->maxLinePerFrag = config->dmaBufferLine;
  979. handle->dmaBytePerLine = config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
  980. handle->isDmaBufferCachable = config->isDmaBufferCachable;
  981. /* Get instance from peripheral base address. */
  982. instance = CSI_GetInstance(base);
  983. /* Save the handle in global variables to support the double weak mechanism. */
  984. s_csiHandle[instance] = handle;
  985. s_csiIsr = CSI_FragModeTransferHandleIRQ;
  986. (void)EnableIRQ(s_csiIRQ[instance]);
  987. /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
  988. reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CR1_FCC_MASK;
  989. if (config->useExtVsync)
  990. {
  991. reg |= CSI_CR1_EXT_VSYNC_MASK;
  992. }
  993. CSI_REG_CR1(base) = reg;
  994. /* No stride. */
  995. CSI_REG_FBUF_PARA(base) = 0;
  996. /* Enable auto ECC. */
  997. CSI_REG_CR3(base) |= CSI_CR3_ECC_AUTO_EN_MASK;
  998. /*
  999. * For better performance.
  1000. * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
  1001. * choose the best burst size based on bytes per line.
  1002. */
  1003. if (0U == (imgWidth_Bytes % (8U * 16U)))
  1004. {
  1005. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(3U);
  1006. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((2U << CSI_CR3_RxFF_LEVEL_SHIFT));
  1007. }
  1008. else if (0U == (imgWidth_Bytes % (8U * 8U)))
  1009. {
  1010. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(2U);
  1011. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((1U << CSI_CR3_RxFF_LEVEL_SHIFT));
  1012. }
  1013. else
  1014. {
  1015. CSI_REG_CR2(base) = CSI_CR2_DMA_BURST_TYPE_RFF(1U);
  1016. CSI_REG_CR3(base) = (CSI_REG_CR3(base) & ~CSI_CR3_RxFF_LEVEL_MASK) | ((0U << CSI_CR3_RxFF_LEVEL_SHIFT));
  1017. }
  1018. CSI_REG_DMASA_FB1(base) = CSI_ADDR_CPU_2_IP(config->dmaBufferAddr0);
  1019. CSI_REG_DMASA_FB2(base) = CSI_ADDR_CPU_2_IP(config->dmaBufferAddr1);
  1020. if (handle->isDmaBufferCachable)
  1021. {
  1022. DCACHE_CleanInvalidateByRange(
  1023. config->dmaBufferAddr0,
  1024. (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
  1025. DCACHE_CleanInvalidateByRange(
  1026. config->dmaBufferAddr1,
  1027. (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
  1028. }
  1029. return kStatus_Success;
  1030. }
  1031. /*!
  1032. * brief Start to capture a image.
  1033. *
  1034. * param base CSI peripheral base address.
  1035. * param handle Pointer to the transactional handle.
  1036. * param config Pointer to the capture configuration.
  1037. *
  1038. * retval kStatus_Success Initialize successfully.
  1039. * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
  1040. */
  1041. status_t CSI_FragModeTransferCaptureImage(CSI_Type *base,
  1042. csi_frag_handle_t *handle,
  1043. const csi_frag_capture_config_t *config)
  1044. {
  1045. assert(NULL != config);
  1046. uint16_t windowWidth;
  1047. /*
  1048. * If no special window setting, capture full frame.
  1049. * If capture window, then capture 1 one each fragment.
  1050. */
  1051. if (config->window != NULL)
  1052. {
  1053. handle->windowULX = config->window->windowULX;
  1054. handle->windowULY = config->window->windowULY;
  1055. handle->windowLRX = config->window->windowLRX;
  1056. handle->windowLRY = config->window->windowLRY;
  1057. handle->linePerFrag = 1;
  1058. }
  1059. else
  1060. {
  1061. handle->windowULX = 0;
  1062. handle->windowULY = 0;
  1063. handle->windowLRX = handle->width - 1U;
  1064. handle->windowLRY = handle->height - 1U;
  1065. handle->linePerFrag = handle->maxLinePerFrag;
  1066. }
  1067. windowWidth = handle->windowLRX - handle->windowULX + 1U;
  1068. if (config->outputGrayScale)
  1069. {
  1070. /* When output format is gray, the window width must be multiple value of 8. */
  1071. if (windowWidth % 8U != 0U)
  1072. {
  1073. return kStatus_InvalidArgument;
  1074. }
  1075. handle->datBytePerLine = windowWidth;
  1076. if (handle->inputFormat == kCSI_FragInputYUYV)
  1077. {
  1078. handle->copyFunc = CSI_ExtractYFromYUYV;
  1079. }
  1080. else
  1081. {
  1082. handle->copyFunc = CSI_ExtractYFromUYVY;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. handle->datBytePerLine = windowWidth * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
  1088. handle->copyFunc = CSI_MemCopy;
  1089. }
  1090. handle->dmaCurLine = 0;
  1091. handle->outputBuffer = (uint32_t)config->buffer;
  1092. handle->datCurWriteAddr = (uint32_t)config->buffer;
  1093. /* Image parameter. */
  1094. CSI_REG_IMAG_PARA(base) =
  1095. (((uint32_t)handle->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL) << CSI_IMAG_PARA_IMAGE_WIDTH_SHIFT) |
  1096. ((uint32_t)(handle->linePerFrag) << CSI_IMAG_PARA_IMAGE_HEIGHT_SHIFT);
  1097. /*
  1098. * Write to memory from first completed frame.
  1099. * DMA base addr switch at dma transfer done.
  1100. */
  1101. CSI_REG_CR18(base) = (CSI_REG_CR18(base) & ~CSI_CR18_MASK_OPTION_MASK) | CSI_CR18_MASK_OPTION(0);
  1102. CSI_EnableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
  1103. (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
  1104. (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
  1105. return kStatus_Success;
  1106. }
  1107. /*!
  1108. * brief Abort image capture.
  1109. *
  1110. * Abort image capture initialized by ref CSI_FragModeTransferCaptureImage.
  1111. *
  1112. * param base CSI peripheral base address.
  1113. * param handle Pointer to the transactional handle.
  1114. */
  1115. void CSI_FragModeTransferAbortCaptureImage(CSI_Type *base, csi_frag_handle_t *handle)
  1116. {
  1117. CSI_Stop(base);
  1118. CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
  1119. (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
  1120. (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
  1121. }
  1122. /*!
  1123. * brief CSI IRQ handle function.
  1124. *
  1125. * This function handles the CSI IRQ request to work with CSI driver fragment mode
  1126. * APIs.
  1127. *
  1128. * param base CSI peripheral base address.
  1129. * param handle CSI handle pointer.
  1130. */
  1131. void CSI_FragModeTransferHandleIRQ(CSI_Type *base, csi_frag_handle_t *handle)
  1132. {
  1133. uint32_t csisr = CSI_REG_SR(base);
  1134. uint32_t dmaBufAddr;
  1135. uint16_t line;
  1136. pvoid_to_u32_t memSrc;
  1137. pvoid_to_u32_t memDest;
  1138. /* Clear the error flags. */
  1139. CSI_REG_SR(base) = csisr;
  1140. /* Start of frame, clear the FIFO and start receiving. */
  1141. if (0U != (csisr & (uint32_t)kCSI_StartOfFrameFlag))
  1142. {
  1143. /* Reflash the DMA and enable RX DMA request. */
  1144. CSI_REG_CR3(base) |= (CSI_CR3_DMA_REFLASH_RFF_MASK | CSI_CR3_DMA_REQ_EN_RFF_MASK);
  1145. CSI_Start(base);
  1146. handle->dmaCurLine = 0;
  1147. handle->datCurWriteAddr = handle->outputBuffer;
  1148. }
  1149. else if ((csisr & (CSI_SR_DMA_TSF_DONE_FB2_MASK | CSI_SR_DMA_TSF_DONE_FB1_MASK)) != 0U)
  1150. {
  1151. if ((csisr & CSI_SR_DMA_TSF_DONE_FB1_MASK) == CSI_SR_DMA_TSF_DONE_FB1_MASK)
  1152. {
  1153. dmaBufAddr = CSI_REG_DMASA_FB1(base);
  1154. }
  1155. else
  1156. {
  1157. dmaBufAddr = CSI_REG_DMASA_FB2(base);
  1158. }
  1159. dmaBufAddr = CSI_ADDR_IP_2_CPU(dmaBufAddr);
  1160. if (handle->isDmaBufferCachable)
  1161. {
  1162. DCACHE_InvalidateByRange(dmaBufAddr, (uint32_t)handle->dmaBytePerLine * (uint32_t)handle->linePerFrag);
  1163. }
  1164. /* Copy from DMA buffer to user data buffer. */
  1165. dmaBufAddr += ((uint32_t)handle->windowULX * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
  1166. for (line = 0; line < handle->linePerFrag; line++)
  1167. {
  1168. if (handle->dmaCurLine + line > handle->windowLRY)
  1169. {
  1170. /* out of window range */
  1171. break;
  1172. }
  1173. else if (handle->dmaCurLine + line >= handle->windowULY)
  1174. {
  1175. memDest.u32 = handle->datCurWriteAddr;
  1176. memSrc.u32 = dmaBufAddr;
  1177. handle->copyFunc(memDest.pvoid, memSrc.pvoid, handle->datBytePerLine);
  1178. handle->datCurWriteAddr += handle->datBytePerLine;
  1179. dmaBufAddr += handle->dmaBytePerLine;
  1180. }
  1181. else
  1182. {
  1183. ; /* For MISRA C-2012 Rule 15.7 */
  1184. }
  1185. }
  1186. handle->dmaCurLine += handle->linePerFrag;
  1187. if (handle->dmaCurLine >= handle->height)
  1188. {
  1189. CSI_Stop(base);
  1190. CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
  1191. (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
  1192. (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
  1193. /* Image captured. Stop the CSI. */
  1194. if (NULL != handle->callback)
  1195. {
  1196. handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
  1197. }
  1198. }
  1199. }
  1200. else
  1201. {
  1202. }
  1203. }
  1204. #endif /* CSI_DRIVER_FRAG_MODE */
  1205. #if defined(CSI)
  1206. void CSI_DriverIRQHandler(void);
  1207. void CSI_DriverIRQHandler(void)
  1208. {
  1209. s_csiIsr(CSI, s_csiHandle[0]);
  1210. SDK_ISR_EXIT_BARRIER;
  1211. }
  1212. #endif
  1213. #if defined(CSI0)
  1214. void CSI0_DriverIRQHandler(void);
  1215. void CSI0_DriverIRQHandler(void)
  1216. {
  1217. s_csiIsr(CSI, s_csiHandle[0]);
  1218. SDK_ISR_EXIT_BARRIER;
  1219. }
  1220. #endif