mbed
Fork of mbed-dev by
targets/TARGET_NUVOTON/TARGET_NANO100/dma_api.c@182:57724642e740, 2018-02-16 (annotated)
- Committer:
- AnnaBridge
- Date:
- Fri Feb 16 16:09:33 2018 +0000
- Revision:
- 182:57724642e740
- Parent:
- 175:b96e65c34a4d
mbed-dev library. Release version 159.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 175:b96e65c34a4d | 1 | /* mbed Microcontroller Library |
AnnaBridge | 175:b96e65c34a4d | 2 | * Copyright (c) 2015-2017 Nuvoton |
AnnaBridge | 175:b96e65c34a4d | 3 | * |
AnnaBridge | 175:b96e65c34a4d | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 175:b96e65c34a4d | 5 | * you may not use this file except in compliance with the License. |
AnnaBridge | 175:b96e65c34a4d | 6 | * You may obtain a copy of the License at |
AnnaBridge | 175:b96e65c34a4d | 7 | * |
AnnaBridge | 175:b96e65c34a4d | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 175:b96e65c34a4d | 9 | * |
AnnaBridge | 175:b96e65c34a4d | 10 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 175:b96e65c34a4d | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 175:b96e65c34a4d | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 175:b96e65c34a4d | 13 | * See the License for the specific language governing permissions and |
AnnaBridge | 175:b96e65c34a4d | 14 | * limitations under the License. |
AnnaBridge | 175:b96e65c34a4d | 15 | */ |
AnnaBridge | 175:b96e65c34a4d | 16 | |
AnnaBridge | 175:b96e65c34a4d | 17 | #include "dma_api.h" |
AnnaBridge | 175:b96e65c34a4d | 18 | #include "string.h" |
AnnaBridge | 175:b96e65c34a4d | 19 | #include "cmsis.h" |
AnnaBridge | 175:b96e65c34a4d | 20 | #include "mbed_assert.h" |
AnnaBridge | 175:b96e65c34a4d | 21 | #include "PeripheralNames.h" |
AnnaBridge | 175:b96e65c34a4d | 22 | #include "nu_modutil.h" |
AnnaBridge | 175:b96e65c34a4d | 23 | #include "nu_bitutil.h" |
AnnaBridge | 175:b96e65c34a4d | 24 | #include "dma.h" |
AnnaBridge | 175:b96e65c34a4d | 25 | |
AnnaBridge | 175:b96e65c34a4d | 26 | #define NU_PDMA_CH_MAX 6 /* Specify maximum channels of PDMA */ |
AnnaBridge | 175:b96e65c34a4d | 27 | #define NU_PDMA_CH_Pos 1 /* Specify first channel number of PDMA */ |
AnnaBridge | 175:b96e65c34a4d | 28 | #define NU_PDMA_CH_Msk (((1 << NU_PDMA_CH_MAX) - 1) << NU_PDMA_CH_Pos) |
AnnaBridge | 175:b96e65c34a4d | 29 | |
AnnaBridge | 175:b96e65c34a4d | 30 | struct nu_dma_chn_s { |
AnnaBridge | 175:b96e65c34a4d | 31 | void (*handler)(uint32_t, uint32_t); |
AnnaBridge | 175:b96e65c34a4d | 32 | uint32_t id; |
AnnaBridge | 175:b96e65c34a4d | 33 | uint32_t event; |
AnnaBridge | 175:b96e65c34a4d | 34 | }; |
AnnaBridge | 175:b96e65c34a4d | 35 | |
AnnaBridge | 175:b96e65c34a4d | 36 | static int dma_inited = 0; |
AnnaBridge | 175:b96e65c34a4d | 37 | static uint32_t dma_chn_mask = 0; |
AnnaBridge | 175:b96e65c34a4d | 38 | static struct nu_dma_chn_s dma_chn_arr[NU_PDMA_CH_MAX]; |
AnnaBridge | 175:b96e65c34a4d | 39 | static const DMAName dmaname_chn_arr[NU_PDMA_CH_MAX] = { |
AnnaBridge | 175:b96e65c34a4d | 40 | // NOTE: DMA_0_0 for VDMA |
AnnaBridge | 175:b96e65c34a4d | 41 | DMA_1_0, DMA_2_0, DMA_3_0, DMA_4_0, DMA_5_0, DMA_6_0 |
AnnaBridge | 175:b96e65c34a4d | 42 | }; |
AnnaBridge | 175:b96e65c34a4d | 43 | |
AnnaBridge | 175:b96e65c34a4d | 44 | void PDMA_IRQHandler(void); |
AnnaBridge | 175:b96e65c34a4d | 45 | static const struct nu_modinit_s dma_modinit = {DMAGCR_0, DMA_MODULE, 0, 0, DMA_RST, PDMA_IRQn, (void *) PDMA_IRQHandler}; |
AnnaBridge | 175:b96e65c34a4d | 46 | |
AnnaBridge | 175:b96e65c34a4d | 47 | |
AnnaBridge | 175:b96e65c34a4d | 48 | void dma_init(void) |
AnnaBridge | 175:b96e65c34a4d | 49 | { |
AnnaBridge | 175:b96e65c34a4d | 50 | if (dma_inited) { |
AnnaBridge | 175:b96e65c34a4d | 51 | return; |
AnnaBridge | 175:b96e65c34a4d | 52 | } |
AnnaBridge | 175:b96e65c34a4d | 53 | |
AnnaBridge | 175:b96e65c34a4d | 54 | dma_inited = 1; |
AnnaBridge | 175:b96e65c34a4d | 55 | dma_chn_mask = ~NU_PDMA_CH_Msk; |
AnnaBridge | 175:b96e65c34a4d | 56 | memset(dma_chn_arr, 0x00, sizeof (dma_chn_arr)); |
AnnaBridge | 175:b96e65c34a4d | 57 | |
AnnaBridge | 175:b96e65c34a4d | 58 | // Reset this module |
AnnaBridge | 175:b96e65c34a4d | 59 | SYS_ResetModule(dma_modinit.rsetidx); |
AnnaBridge | 175:b96e65c34a4d | 60 | |
AnnaBridge | 175:b96e65c34a4d | 61 | // Enable IP clock |
AnnaBridge | 175:b96e65c34a4d | 62 | CLK_EnableModuleClock(dma_modinit.clkidx); |
AnnaBridge | 175:b96e65c34a4d | 63 | |
AnnaBridge | 175:b96e65c34a4d | 64 | PDMA_Open(0); |
AnnaBridge | 175:b96e65c34a4d | 65 | |
AnnaBridge | 175:b96e65c34a4d | 66 | NVIC_SetVector(dma_modinit.irq_n, (uint32_t) dma_modinit.var); |
AnnaBridge | 175:b96e65c34a4d | 67 | NVIC_EnableIRQ(dma_modinit.irq_n); |
AnnaBridge | 175:b96e65c34a4d | 68 | } |
AnnaBridge | 175:b96e65c34a4d | 69 | |
AnnaBridge | 175:b96e65c34a4d | 70 | int dma_channel_allocate(uint32_t capabilities) |
AnnaBridge | 175:b96e65c34a4d | 71 | { |
AnnaBridge | 175:b96e65c34a4d | 72 | if (! dma_inited) { |
AnnaBridge | 175:b96e65c34a4d | 73 | dma_init(); |
AnnaBridge | 175:b96e65c34a4d | 74 | } |
AnnaBridge | 175:b96e65c34a4d | 75 | |
AnnaBridge | 175:b96e65c34a4d | 76 | int i = nu_cto(dma_chn_mask); |
AnnaBridge | 175:b96e65c34a4d | 77 | if (i != 32) { |
AnnaBridge | 175:b96e65c34a4d | 78 | dma_chn_mask |= 1 << i; |
AnnaBridge | 175:b96e65c34a4d | 79 | memset(dma_chn_arr + i - NU_PDMA_CH_Pos, 0x00, sizeof (struct nu_dma_chn_s)); |
AnnaBridge | 175:b96e65c34a4d | 80 | return i; |
AnnaBridge | 175:b96e65c34a4d | 81 | } |
AnnaBridge | 175:b96e65c34a4d | 82 | |
AnnaBridge | 175:b96e65c34a4d | 83 | // No channel available |
AnnaBridge | 175:b96e65c34a4d | 84 | return DMA_ERROR_OUT_OF_CHANNELS; |
AnnaBridge | 175:b96e65c34a4d | 85 | } |
AnnaBridge | 175:b96e65c34a4d | 86 | |
AnnaBridge | 175:b96e65c34a4d | 87 | int dma_channel_free(int channelid) |
AnnaBridge | 175:b96e65c34a4d | 88 | { |
AnnaBridge | 175:b96e65c34a4d | 89 | if (channelid != DMA_ERROR_OUT_OF_CHANNELS) { |
AnnaBridge | 175:b96e65c34a4d | 90 | dma_chn_mask &= ~(1 << channelid); |
AnnaBridge | 175:b96e65c34a4d | 91 | } |
AnnaBridge | 175:b96e65c34a4d | 92 | |
AnnaBridge | 175:b96e65c34a4d | 93 | return 0; |
AnnaBridge | 175:b96e65c34a4d | 94 | } |
AnnaBridge | 175:b96e65c34a4d | 95 | |
AnnaBridge | 175:b96e65c34a4d | 96 | void dma_set_handler(int channelid, uint32_t handler, uint32_t id, uint32_t event) |
AnnaBridge | 175:b96e65c34a4d | 97 | { |
AnnaBridge | 175:b96e65c34a4d | 98 | MBED_ASSERT(dma_chn_mask & (1 << channelid)); |
AnnaBridge | 175:b96e65c34a4d | 99 | |
AnnaBridge | 175:b96e65c34a4d | 100 | dma_chn_arr[channelid - NU_PDMA_CH_Pos].handler = (void (*)(uint32_t, uint32_t)) handler; |
AnnaBridge | 175:b96e65c34a4d | 101 | dma_chn_arr[channelid - NU_PDMA_CH_Pos].id = id; |
AnnaBridge | 175:b96e65c34a4d | 102 | dma_chn_arr[channelid - NU_PDMA_CH_Pos].event = event; |
AnnaBridge | 175:b96e65c34a4d | 103 | |
AnnaBridge | 175:b96e65c34a4d | 104 | // Set interrupt vector if someone has removed it. |
AnnaBridge | 175:b96e65c34a4d | 105 | NVIC_SetVector(dma_modinit.irq_n, (uint32_t) dma_modinit.var); |
AnnaBridge | 175:b96e65c34a4d | 106 | NVIC_EnableIRQ(dma_modinit.irq_n); |
AnnaBridge | 175:b96e65c34a4d | 107 | } |
AnnaBridge | 175:b96e65c34a4d | 108 | |
AnnaBridge | 175:b96e65c34a4d | 109 | PDMA_T *dma_modbase(int channelid) |
AnnaBridge | 175:b96e65c34a4d | 110 | { |
AnnaBridge | 175:b96e65c34a4d | 111 | DMAName dma_name = dmaname_chn_arr[channelid - NU_PDMA_CH_Pos]; |
AnnaBridge | 175:b96e65c34a4d | 112 | return (PDMA_T *) NU_MODBASE(dma_name); |
AnnaBridge | 175:b96e65c34a4d | 113 | } |
AnnaBridge | 175:b96e65c34a4d | 114 | |
AnnaBridge | 175:b96e65c34a4d | 115 | void dma_enable(int channelid, int enable) |
AnnaBridge | 175:b96e65c34a4d | 116 | { |
AnnaBridge | 175:b96e65c34a4d | 117 | DMA_GCR_T *dmagcr_base = (DMA_GCR_T *) NU_MODBASE(dma_modinit.modname); |
AnnaBridge | 175:b96e65c34a4d | 118 | PDMA_T *pdma_base = dma_modbase(channelid); |
AnnaBridge | 175:b96e65c34a4d | 119 | uint32_t pos = channelid - NU_PDMA_CH_Pos + DMA_GCR_GCRCSR_CLK1_EN_Pos; |
AnnaBridge | 175:b96e65c34a4d | 120 | |
AnnaBridge | 175:b96e65c34a4d | 121 | if (enable) { |
AnnaBridge | 175:b96e65c34a4d | 122 | dmagcr_base->GCRCSR |= 1 << pos; // Enable channel clock |
AnnaBridge | 175:b96e65c34a4d | 123 | pdma_base->CSR |= (PDMA_CSR_PDMACEN_Msk); // Enable channel |
AnnaBridge | 175:b96e65c34a4d | 124 | } |
AnnaBridge | 175:b96e65c34a4d | 125 | else { |
AnnaBridge | 175:b96e65c34a4d | 126 | dmagcr_base->GCRCSR &= ~(1 << pos); // Disable channel clock |
AnnaBridge | 175:b96e65c34a4d | 127 | pdma_base->CSR &= ~(PDMA_CSR_PDMACEN_Msk); // Disable channel |
AnnaBridge | 175:b96e65c34a4d | 128 | } |
AnnaBridge | 175:b96e65c34a4d | 129 | } |
AnnaBridge | 175:b96e65c34a4d | 130 | |
AnnaBridge | 175:b96e65c34a4d | 131 | void PDMA_IRQHandler(void) |
AnnaBridge | 175:b96e65c34a4d | 132 | { |
AnnaBridge | 175:b96e65c34a4d | 133 | uint32_t intsts = PDMA_GET_INT_STATUS(); |
AnnaBridge | 175:b96e65c34a4d | 134 | // Just interested in INTR1-INTR6 |
AnnaBridge | 175:b96e65c34a4d | 135 | intsts &= ((NU_PDMA_CH_Msk >> NU_PDMA_CH_Pos) << DMA_GCR_GCRISR_INTR1_Pos); |
AnnaBridge | 175:b96e65c34a4d | 136 | |
AnnaBridge | 175:b96e65c34a4d | 137 | while (intsts) { |
AnnaBridge | 175:b96e65c34a4d | 138 | int chn_id = nu_ctz(intsts) - DMA_GCR_GCRISR_INTR1_Pos + NU_PDMA_CH_Pos; |
AnnaBridge | 175:b96e65c34a4d | 139 | uint32_t intsts_chn = PDMA_GET_CH_INT_STS(chn_id); |
AnnaBridge | 175:b96e65c34a4d | 140 | |
AnnaBridge | 175:b96e65c34a4d | 141 | if (dma_chn_mask & (1 << chn_id)) { |
AnnaBridge | 175:b96e65c34a4d | 142 | struct nu_dma_chn_s *dma_chn = dma_chn_arr + chn_id - NU_PDMA_CH_Pos; |
AnnaBridge | 175:b96e65c34a4d | 143 | |
AnnaBridge | 175:b96e65c34a4d | 144 | // Abort |
AnnaBridge | 175:b96e65c34a4d | 145 | if (intsts_chn & PDMA_ISR_TABORT_IS_Msk) { |
AnnaBridge | 175:b96e65c34a4d | 146 | // Clear ABORT IF of the channel |
AnnaBridge | 175:b96e65c34a4d | 147 | PDMA_CLR_CH_INT_FLAG(chn_id, PDMA_ISR_TABORT_IS_Msk); |
AnnaBridge | 175:b96e65c34a4d | 148 | |
AnnaBridge | 175:b96e65c34a4d | 149 | if (dma_chn->handler && (dma_chn->event & DMA_EVENT_ABORT)) { |
AnnaBridge | 175:b96e65c34a4d | 150 | dma_chn->handler(dma_chn->id, DMA_EVENT_ABORT); |
AnnaBridge | 175:b96e65c34a4d | 151 | } |
AnnaBridge | 175:b96e65c34a4d | 152 | } |
AnnaBridge | 175:b96e65c34a4d | 153 | |
AnnaBridge | 175:b96e65c34a4d | 154 | // Transfer done |
AnnaBridge | 175:b96e65c34a4d | 155 | if (intsts_chn & PDMA_ISR_TD_IS_Msk) { |
AnnaBridge | 175:b96e65c34a4d | 156 | // Clear TD IF of the channel |
AnnaBridge | 175:b96e65c34a4d | 157 | PDMA_CLR_CH_INT_FLAG(chn_id, PDMA_ISR_TD_IS_Msk); |
AnnaBridge | 175:b96e65c34a4d | 158 | |
AnnaBridge | 175:b96e65c34a4d | 159 | if (dma_chn->handler && (dma_chn->event & DMA_EVENT_TRANSFER_DONE)) { |
AnnaBridge | 175:b96e65c34a4d | 160 | dma_chn->handler(dma_chn->id, DMA_EVENT_TRANSFER_DONE); |
AnnaBridge | 175:b96e65c34a4d | 161 | } |
AnnaBridge | 175:b96e65c34a4d | 162 | } |
AnnaBridge | 175:b96e65c34a4d | 163 | |
AnnaBridge | 175:b96e65c34a4d | 164 | // Timeout |
AnnaBridge | 175:b96e65c34a4d | 165 | if (intsts_chn & PDMA_ISR_TO_IS_Msk) { |
AnnaBridge | 175:b96e65c34a4d | 166 | // Clear TIMEOUT IF of the channel |
AnnaBridge | 175:b96e65c34a4d | 167 | PDMA_CLR_CH_INT_FLAG(chn_id, PDMA_ISR_TO_IS_Msk); |
AnnaBridge | 175:b96e65c34a4d | 168 | |
AnnaBridge | 175:b96e65c34a4d | 169 | if (dma_chn->handler && (dma_chn->event & DMA_EVENT_TIMEOUT)) { |
AnnaBridge | 175:b96e65c34a4d | 170 | dma_chn->handler(dma_chn->id, DMA_EVENT_TIMEOUT); |
AnnaBridge | 175:b96e65c34a4d | 171 | } |
AnnaBridge | 175:b96e65c34a4d | 172 | } |
AnnaBridge | 175:b96e65c34a4d | 173 | } |
AnnaBridge | 175:b96e65c34a4d | 174 | |
AnnaBridge | 175:b96e65c34a4d | 175 | intsts &= ~(1 << (chn_id - NU_PDMA_CH_Pos + DMA_GCR_GCRISR_INTR1_Pos)); |
AnnaBridge | 175:b96e65c34a4d | 176 | } |
AnnaBridge | 175:b96e65c34a4d | 177 | } |