GPDMA_LPC18xx.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /* --------------------------------------------------------------------------
  2. * Copyright (c) 2013-2016 ARM Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * $Date: 02. March 2016
  19. * $Revision: V1.3
  20. *
  21. * Project: GPDMA Driver for NXP LPC18xx
  22. * -------------------------------------------------------------------------- */
  23. /* History:
  24. * Version 1.3
  25. * - Corrected transfers bigger than 4k
  26. * Version 1.2
  27. * - Added GPDMA_ChannelGetCount function.
  28. * Version 1.1
  29. * - Updated Initialize and Uninitialize functions
  30. */
  31. #include "LPC18xx.h"
  32. #include "GPDMA_LPC18xx.h"
  33. // GPDMA Channel register block structure
  34. typedef struct {
  35. __IO uint32_t SRCADDR; // DMA Channel Source Address Register
  36. __IO uint32_t DESTADDR; // DMA Channel Destination Address Register
  37. __IO uint32_t LLI; // DMA Channel Linked List Item Register
  38. __IO uint32_t CONTROL; // DMA Channel Control Register
  39. __IO uint32_t CONFIG; // DMA Channel Configuration Register
  40. __I uint32_t RESERVED1[3];
  41. } GPDMA_CHANNEL_REG;
  42. typedef struct {
  43. uint32_t SrcAddr;
  44. uint32_t DestAddr;
  45. uint32_t Size;
  46. uint32_t Cnt;
  47. GPDMA_SignalEvent_t cb_event;
  48. } GPDMA_Channel_Info;
  49. static uint32_t Channel_active = 0U;
  50. static uint32_t Init_cnt = 0U;
  51. static GPDMA_Channel_Info Channel_info[GPDMA_NUMBER_OF_CHANNELS] = { 0U };
  52. #define GPDMA_CHANNEL(n) ((GPDMA_CHANNEL_REG *) (&(LPC_GPDMA->C0SRCADDR) + (n * 8U)))
  53. /**
  54. \fn int32_t Set_Channel_active_flag (uint8_t ch)
  55. \brief Protected set of channel active flag
  56. \param[in] ch Channel number (0..7)
  57. \returns
  58. - \b 0: function succeeded
  59. - \b -1: function failed
  60. */
  61. __inline static int32_t Set_Channel_active_flag (uint8_t ch) {
  62. uint32_t val;
  63. do {
  64. val = __LDREXW (&Channel_active);
  65. if (val & (1U << ch)) {
  66. __CLREX ();
  67. return -1;
  68. }
  69. } while (__STREXW (val | (1U << ch), &Channel_active));
  70. return 0;
  71. }
  72. /**
  73. \fn void Clear_Channel_active_flag (uint8_t ch)
  74. \brief Protected clear of channel active flag
  75. \param[in] ch Channel number (0..7)
  76. */
  77. __inline static void Clear_Channel_active_flag (uint8_t ch) {
  78. while(__STREXW((__LDREXW(&Channel_active) & ~(1U << ch)), &Channel_active));
  79. }
  80. /**
  81. \fn int32_t GPDMA_Initialize (void)
  82. \brief Initialize GPDMA peripheral
  83. \returns
  84. - \b 0: function succeeded
  85. - \b -1: function failed
  86. */
  87. int32_t GPDMA_Initialize (void) {
  88. uint32_t ch_num;
  89. Init_cnt++;
  90. // Check if already initialized
  91. if (Init_cnt > 1U) { return 0; }
  92. // Enable DMA clock
  93. LPC_CCU1->CLK_M3_DMA_CFG |= 1U;
  94. while ((LPC_CCU1->CLK_M3_DMA_STAT & 1U) == 0U);
  95. // Reset DMA
  96. LPC_RGU->RESET_CTRL0 = (1U << 19);
  97. // Reset all DMA channels
  98. for (ch_num = 0U; ch_num < GPDMA_NUMBER_OF_CHANNELS; ch_num++) {
  99. GPDMA_CHANNEL(ch_num)->CONFIG = 0U;
  100. Channel_info[ch_num].SrcAddr = 0U;
  101. Channel_info[ch_num].DestAddr = 0U;
  102. Channel_info[ch_num].Size = 0U;
  103. Channel_info[ch_num].Cnt = 0U;
  104. }
  105. // Clear all DMA interrupt flags
  106. LPC_GPDMA->INTTCCLEAR = 0xFF;
  107. LPC_GPDMA->INTERRCLR = 0xFF;
  108. // Clear and Enable DMA IRQ
  109. NVIC_ClearPendingIRQ(DMA_IRQn);
  110. NVIC_EnableIRQ(DMA_IRQn);
  111. return 0;
  112. }
  113. /**
  114. \fn int32_t GPDMA_Uninitialize (void)
  115. \brief De-initialize GPDMA peripheral
  116. \returns
  117. - \b 0: function succeeded
  118. - \b -1: function failed
  119. */
  120. int32_t GPDMA_Uninitialize (void) {
  121. // Check if DMA is initialized
  122. if (Init_cnt == 0U) { return -1; }
  123. Init_cnt--;
  124. if (Init_cnt != 0U) { return 0; }
  125. // Disable DMA clock
  126. LPC_CCU1->CLK_M3_DMA_CFG &= ~1U;
  127. // Disable and Clear DMA IRQ
  128. NVIC_DisableIRQ(DMA_IRQn);
  129. NVIC_ClearPendingIRQ(DMA_IRQn);
  130. return 0;
  131. }
  132. /**
  133. \fn int32_t GPDMA_PeripheralSelect (uint8_t peri, uint8_t sel)
  134. \brief Selects GPDMA requests
  135. \param[in] peri GPDMA peripheral
  136. \param[in] sel Selects the DMA request for GPDMA input (0..3)
  137. \returns
  138. - \b 0: function succeeded
  139. - \b -1: function failed
  140. */
  141. int32_t GPDMA_PeripheralSelect (uint8_t peri, uint8_t sel) {
  142. if ((peri > 15U) || (sel > 3U)) { return -1; }
  143. LPC_CREG->DMAMUX = (LPC_CREG->DMAMUX & ~(3U << (2U * peri))) | (sel << (2U * peri));
  144. return 0;
  145. }
  146. /**
  147. \fn int32_t GPDMA_ChannelConfigure (uint8_t ch,
  148. uint32_t src_addr,
  149. uint32_t dest_addr,
  150. uint32_t size,
  151. uint32_t control,
  152. uint32_t config,
  153. GPDMA_SignalEvent_t cb_event)
  154. \brief Configure GPDMA channel for next transfer
  155. \param[in] ch Channel number (0..7)
  156. \param[in] src_addr Source address
  157. \param[in] dest_addr Destination address
  158. \param[in] size Amount of data to transfer
  159. \param[in] control Channel control
  160. \param[in] config Channel configuration
  161. \param[in] cb_event Channel callback pointer
  162. \returns
  163. - \b 0: function succeeded
  164. - \b -1: function failed
  165. */
  166. int32_t GPDMA_ChannelConfigure (uint8_t ch,
  167. uint32_t src_addr,
  168. uint32_t dest_addr,
  169. uint32_t size,
  170. uint32_t control,
  171. uint32_t config,
  172. GPDMA_SignalEvent_t cb_event) {
  173. GPDMA_CHANNEL_REG * dma_ch;
  174. // Check if channel is valid
  175. if (ch >= GPDMA_NUMBER_OF_CHANNELS) { return -1; }
  176. // Set Channel active flag
  177. if (Set_Channel_active_flag (ch) == -1) { return -1; }
  178. // Save callback pointer
  179. Channel_info[ch].cb_event = cb_event;
  180. dma_ch = GPDMA_CHANNEL(ch);
  181. // Reset DMA Channel configuration
  182. dma_ch->CONFIG = 0U;
  183. dma_ch->CONTROL = 0U;
  184. // Clear DMA interrupts
  185. LPC_GPDMA->INTTCCLEAR = (1U << ch);
  186. LPC_GPDMA->INTERRCLR = (1U << ch);
  187. // Link list not supported
  188. dma_ch->LLI = 0U;
  189. // Enable DMA Channels, little endian
  190. LPC_GPDMA->CONFIG = GPDMA_CONFIG_E;
  191. while ((LPC_GPDMA->CONFIG & GPDMA_CONFIG_E) == 0U);
  192. Channel_info[ch].Size = size;
  193. if (size > 0x0FFFU) {
  194. // Max DMA transfer size = 4k
  195. size = 0x0FFFU;
  196. }
  197. control = (control & ~GPDMA_CH_CONTROL_TRANSFERSIZE_MSK) | GPDMA_CH_CONTROL_TRANSFERSIZE(size);
  198. // Set Source and destination address
  199. dma_ch->SRCADDR = src_addr;
  200. dma_ch->DESTADDR = dest_addr;
  201. if (control & GPDMA_CH_CONTROL_SI) {
  202. // Source address increment
  203. src_addr += (size << ((control & GPDMA_CH_CONTROL_SWIDTH_MSK) >> GPDMA_CH_CONTROL_SWIDTH_POS));
  204. }
  205. if (control & GPDMA_CH_CONTROL_DI) {
  206. // Destination address increment
  207. dest_addr += (size << ((control & GPDMA_CH_CONTROL_DWIDTH_MSK) >> GPDMA_CH_CONTROL_DWIDTH_POS));
  208. }
  209. // Save channel information
  210. Channel_info[ch].SrcAddr = src_addr;
  211. Channel_info[ch].DestAddr = dest_addr;
  212. Channel_info[ch].Cnt = size;
  213. dma_ch->CONTROL = control;
  214. dma_ch->CONFIG = config;
  215. if ((config & GPDMA_CONFIG_E) == 0U) {
  216. // Clear Channel active flag
  217. Clear_Channel_active_flag (ch);
  218. }
  219. return 0;
  220. }
  221. /**
  222. \fn int32_t GPDMA_ChannelEnable (uint8_t ch)
  223. \brief Enable GPDMA channel
  224. \param[in] ch Channel number (0..7)
  225. \returns
  226. - \b 0: function succeeded
  227. - \b -1: function failed
  228. */
  229. int32_t GPDMA_ChannelEnable (uint8_t ch) {
  230. // Check if channel is valid
  231. if (ch >= GPDMA_NUMBER_OF_CHANNELS) { return -1; }
  232. // Set Channel active flag
  233. if (Set_Channel_active_flag (ch) == -1) { return -1; }
  234. GPDMA_CHANNEL(ch)->CONFIG |= GPDMA_CH_CONFIG_E;
  235. return 0;
  236. }
  237. /**
  238. \fn int32_t GPDMA_ChannelDisable (uint8_t ch)
  239. \brief Disable GPDMA channel
  240. \param[in] ch Channel number (0..7)
  241. \returns
  242. - \b 0: function succeeded
  243. - \b -1: function failed
  244. */
  245. int32_t GPDMA_ChannelDisable (uint8_t ch) {
  246. // Check if channel is valid
  247. if (ch >= GPDMA_NUMBER_OF_CHANNELS) { return -1; }
  248. // Clear Channel active flag
  249. Clear_Channel_active_flag (ch);
  250. GPDMA_CHANNEL(ch)->CONFIG &= ~GPDMA_CH_CONFIG_E;
  251. return 0;
  252. }
  253. /**
  254. \fn uint32_t GPDMA_ChannelGetStatus (uint8_t ch)
  255. \brief Check if GPDMA channel is enabled or disabled
  256. \param[in] ch Channel number (0..7)
  257. \returns Channel status
  258. - \b 1: channel enabled
  259. - \b 0: channel disabled
  260. */
  261. uint32_t GPDMA_ChannelGetStatus (uint8_t ch) {
  262. // Check if channel is valid
  263. if (ch >= GPDMA_NUMBER_OF_CHANNELS) { return 0U; };
  264. if (Channel_active & (1 << ch)) { return 1U; }
  265. else { return 0U; }
  266. }
  267. /**
  268. \fn uint32_t GPDMA_ChannelGetCount (uint8_t ch)
  269. \brief Get number of transferred data
  270. \param[in] ch Channel number (0..7)
  271. \returns Number of transferred data
  272. */
  273. uint32_t GPDMA_ChannelGetCount (uint8_t ch) {
  274. // Check if channel is valid
  275. if (ch >= GPDMA_NUMBER_OF_CHANNELS) return 0;
  276. return (Channel_info[ch].Cnt - (GPDMA_CHANNEL(ch)->CONTROL & GPDMA_CH_CONTROL_TRANSFERSIZE_MSK));
  277. }
  278. /**
  279. \fn void DMA_IRQHandler (void)
  280. \brief DMA interrupt handler
  281. */
  282. void DMA_IRQHandler (void) {
  283. uint32_t ch, size;
  284. GPDMA_CHANNEL_REG * dma_ch;
  285. for (ch = 0; ch < GPDMA_NUMBER_OF_CHANNELS; ch++) {
  286. if (LPC_GPDMA->INTSTAT & (1U << ch)) {
  287. dma_ch = GPDMA_CHANNEL(ch);
  288. // Terminal count request interrupt
  289. if (LPC_GPDMA->INTTCSTAT & (1U << ch)) {
  290. // Clear interrupt flag
  291. LPC_GPDMA->INTTCCLEAR = (1U << ch);
  292. if (Channel_info[ch].Cnt != Channel_info[ch].Size) {
  293. // Data waiting to transfer
  294. size = Channel_info[ch].Size - Channel_info[ch].Cnt;
  295. // Max DMA transfer size = 4k
  296. if (size > 0x0FFFU) { size = 0x0FFFU; }
  297. Channel_info[ch].Cnt += size;
  298. if (dma_ch->CONTROL & GPDMA_CH_CONTROL_SI) {
  299. // Source Address Increment
  300. dma_ch->SRCADDR = Channel_info[ch].SrcAddr;
  301. Channel_info[ch].SrcAddr += (size << ((dma_ch->CONTROL & GPDMA_CH_CONTROL_SWIDTH_MSK) >> GPDMA_CH_CONTROL_SWIDTH_POS));
  302. }
  303. if (dma_ch->CONTROL & GPDMA_CH_CONTROL_DI) {
  304. // Destination address increment
  305. dma_ch->DESTADDR = Channel_info[ch].DestAddr;
  306. Channel_info[ch].DestAddr += (size << ((dma_ch->CONTROL & GPDMA_CH_CONTROL_DWIDTH_MSK) >> GPDMA_CH_CONTROL_DWIDTH_POS));
  307. }
  308. // Set transfer size
  309. dma_ch->CONTROL = (dma_ch->CONTROL & ~GPDMA_CH_CONTROL_TRANSFERSIZE_MSK) | GPDMA_CH_CONTROL_TRANSFERSIZE(size);
  310. // Enable DMA Channel
  311. dma_ch->CONFIG |= GPDMA_CH_CONFIG_E;
  312. } else {
  313. // All Data has been transferred
  314. // Clear Channel active flag
  315. Clear_Channel_active_flag (ch);
  316. // Signal Event
  317. if (Channel_info[ch].cb_event) {
  318. Channel_info[ch].cb_event(GPDMA_EVENT_TERMINAL_COUNT_REQUEST);
  319. }
  320. }
  321. } else {
  322. // DMA error interrupt
  323. if (LPC_GPDMA->INTERRSTAT & (1U << ch)) {
  324. dma_ch->CONFIG = 0U;
  325. dma_ch->CONTROL = 0U;
  326. // Clear Channel active flag
  327. Clear_Channel_active_flag (ch);
  328. // Clear interrupt flag
  329. LPC_GPDMA->INTERRCLR = (1U << ch);
  330. // Signal Event
  331. if (Channel_info[ch].cb_event) {
  332. Channel_info[ch].cb_event(GPDMA_EVENT_ERROR);
  333. }
  334. }
  335. }
  336. }
  337. }
  338. }