APM:Libraries
shared_dma.cpp
Go to the documentation of this file.
1 /*
2  * This file is free software: you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published by the
4  * Free Software Foundation, either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * This file is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  * See the GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License along
13  * with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  * Code by Andrew Tridgell and Siddharth Bharat Purohit
16  */
17 #include "shared_dma.h"
18 
19 /*
20  code to handle sharing of DMA channels between peripherals
21  */
22 
23 using namespace ChibiOS;
24 
26 
27 void Shared_DMA::init(void)
28 {
29  for (uint8_t i=0; i<SHARED_DMA_MAX_STREAM_ID; i++) {
30  chBSemObjectInit(&locks[i].semaphore, false);
31  }
32 }
33 
34 // constructor
35 Shared_DMA::Shared_DMA(uint8_t _stream_id1,
36  uint8_t _stream_id2,
37  dma_allocate_fn_t _allocate,
38  dma_deallocate_fn_t _deallocate)
39 {
40  stream_id1 = _stream_id1;
41  stream_id2 = _stream_id2;
42  allocate = _allocate;
43  deallocate = _deallocate;
44 }
45 
46 //remove any assigned deallocator or allocator
48 {
49  if (locks[stream_id1].obj == this) {
51  locks[stream_id1].obj = nullptr;
52  }
53 
54  if (locks[stream_id2].obj == this) {
56  locks[stream_id2].obj = nullptr;
57  }
58 }
59 
60 // lock the DMA channels
62 {
63  // see if another driver has DMA allocated. If so, call their
64  // deallocation function
65  if (stream_id1 != SHARED_DMA_NONE &&
66  locks[stream_id1].obj && locks[stream_id1].obj != this) {
68  locks[stream_id1].obj = nullptr;
69  }
70  if (stream_id2 != SHARED_DMA_NONE &&
71  locks[stream_id2].obj && locks[stream_id2].obj != this) {
73  locks[stream_id2].obj = nullptr;
74  }
75  if ((stream_id1 != SHARED_DMA_NONE && locks[stream_id1].obj == nullptr) ||
76  (stream_id2 != SHARED_DMA_NONE && locks[stream_id2].obj == nullptr)) {
77  // allocate the DMA channels and put our deallocation function in place
78  allocate(this);
79  if (stream_id1 != SHARED_DMA_NONE) {
81  locks[stream_id1].obj = this;
82  }
83  if (stream_id2 != SHARED_DMA_NONE) {
85  locks[stream_id2].obj = this;
86  }
87  }
88  have_lock = true;
89 }
90 
91 // lock the DMA channels, blocking method
92 void Shared_DMA::lock(void)
93 {
94  if (stream_id1 != SHARED_DMA_NONE) {
95  chBSemWait(&locks[stream_id1].semaphore);
96  }
97  if (stream_id2 != SHARED_DMA_NONE) {
98  chBSemWait(&locks[stream_id2].semaphore);
99  }
100  lock_core();
101 }
102 
103 // lock the DMA channels, non-blocking
105 {
106  if (stream_id1 != SHARED_DMA_NONE) {
107  if (chBSemWaitTimeout(&locks[stream_id1].semaphore, 1) != MSG_OK) {
108  chSysDisable();
109  if (locks[stream_id1].obj != nullptr && locks[stream_id1].obj != this) {
110  locks[stream_id1].obj->contention = true;
111  }
112  chSysEnable();
113  contention = true;
114  return false;
115  }
116  }
117  if (stream_id2 != SHARED_DMA_NONE) {
118  if (chBSemWaitTimeout(&locks[stream_id2].semaphore, 1) != MSG_OK) {
119  if (stream_id1 != SHARED_DMA_NONE) {
120  chBSemSignal(&locks[stream_id1].semaphore);
121  }
122  chSysDisable();
123  if (locks[stream_id2].obj != nullptr && locks[stream_id2].obj != this) {
124  locks[stream_id2].obj->contention = true;
125  }
126  chSysEnable();
127  contention = true;
128  return false;
129  }
130  }
131  lock_core();
132  return true;
133 }
134 
135 // unlock the DMA channels
137 {
138  osalDbgAssert(have_lock, "must have lock");
139  if (stream_id2 != SHARED_DMA_NONE) {
140  chBSemSignal(&locks[stream_id2].semaphore);
141  }
142  if (stream_id1 != SHARED_DMA_NONE) {
143  chBSemSignal(&locks[stream_id1].semaphore);
144  }
145  have_lock = false;
146 }
147 
148 // unlock the DMA channels from a lock zone
150 {
151  osalDbgAssert(have_lock, "must have lock");
152  if (stream_id2 != SHARED_DMA_NONE) {
153  chBSemSignalI(&locks[stream_id2].semaphore);
154  chSchRescheduleS();
155  }
156  if (stream_id1 != SHARED_DMA_NONE) {
157  chBSemSignalI(&locks[stream_id1].semaphore);
158  chSchRescheduleS();
159  }
160  have_lock = false;
161 }
162 
163 // unlock the DMA channels from an IRQ
165 {
166  osalDbgAssert(have_lock, "must have lock");
167  chSysLockFromISR();
168  if (stream_id2 != SHARED_DMA_NONE) {
169  chBSemSignalI(&locks[stream_id2].semaphore);
170  }
171  if (stream_id1 != SHARED_DMA_NONE) {
172  chBSemSignalI(&locks[stream_id1].semaphore);
173  }
174  have_lock = false;
175  chSysUnlockFromISR();
176 }
177 
178 /*
179  lock all channels - used on reboot to ensure no sensor DMA is in
180  progress
181  */
183 {
184  for (uint8_t i=0; i<SHARED_DMA_MAX_STREAM_ID; i++) {
185  chBSemWait(&locks[i].semaphore);
186  }
187 }
dma_allocate_fn_t deallocate
Definition: shared_dma.h:70
Shared_DMA(uint8_t stream_id1, uint8_t stream_id2, dma_allocate_fn_t allocate, dma_allocate_fn_t deallocate)
Definition: shared_dma.cpp:35
void unlock_from_lockzone(void)
Definition: shared_dma.cpp:149
void unregister(void)
Definition: shared_dma.cpp:47
static struct ChibiOS::Shared_DMA::dma_lock locks[SHARED_DMA_MAX_STREAM_ID]
Definition: shared_dma.cpp:25
dma_deallocate_fn_t deallocate
Definition: shared_dma.h:87
#define SHARED_DMA_NONE
Definition: shared_dma.h:24
bool lock_nonblock(void)
Definition: shared_dma.cpp:104
void unlock_from_IRQ(void)
Definition: shared_dma.cpp:164
static void lock_all(void)
Definition: shared_dma.cpp:182
static void init(void)
Definition: shared_dma.cpp:27
dma_allocate_fn_t allocate
Definition: shared_dma.h:69
void lock_core(void)
Definition: shared_dma.cpp:61
#define SHARED_DMA_MAX_STREAM_ID
Definition: shared_dma.h:21