@@ -32,9 +32,6 @@ namespace klib::core::lpc17xx::io::detail::dma {
3232 *
3333 */
3434 struct transfer_helper {
35- // pointer to the start of the data
36- uint8_t * data;
37-
3835 // requested size of the current endpoint
3936 uint32_t requested_size;
4037
@@ -203,10 +200,10 @@ namespace klib::core::lpc17xx::io {
203200 *
204201 */
205202 static void irq_handler () {
206- // make sure we have a valid pointer to data before we do anything
207- if (! helper.data ) [[unlikely]] {
208- // if the pointer is invalid it means we are finished with the
209- // transfer. Call the callback when this happens if we have one
203+ // check if we are done transmitting/receiving
204+ if (helper.transferred_size >= helper. requested_size ) [[unlikely]] {
205+ // we are finished with the transfer. Call the callback
206+ // when this happens if we have one
210207 if (helper.callback ) {
211208 // call the callback
212209 helper.callback ();
@@ -218,59 +215,42 @@ namespace klib::core::lpc17xx::io {
218215 return ;
219216 }
220217
221- // check what type of transfer we were doing
222- if constexpr (std::is_same_v<Source, klib::io::dma::memory> &&
223- !std::is_same_v<Destination, klib::io::dma::memory>)
224- {
225- peripheral_memory_impl<true >();
226- }
227- else if constexpr (!std::is_same_v<Source, klib::io::dma::memory> &&
228- std::is_same_v<Destination, klib::io::dma::memory>)
229- {
230- peripheral_memory_impl<false >();
231- }
232- else if constexpr (std::is_same_v<Source, klib::io::dma::memory> &&
233- std::is_same_v<Destination, klib::io::dma::memory>)
234- {
235- // TODO: implement m2m
236- }
237- else {
238- // TODO: implement p2p
239- }
218+ // prepare the next interrupt
219+ peripheral_memory_impl<true >();
240220 }
241221
242222 /* *
243223 * @brief Memory to peripheral implementation
244224 *
245225 */
246- template <bool M2P >
226+ template <bool Increment >
247227 static void peripheral_memory_impl () {
248228 // get the amount of data we still have to send
249229 const auto transfer_size = (helper.requested_size - helper.transferred_size );
250230
251231 // determine the amount we will send in the current transfer
252232 const auto current_transfer = klib::min (transfer_size, 0xfff );
253- const bool needs_irq = transfer_size > 0xfff ;
254233
255- if constexpr (M2P ) {
256- // set the source and destination
257- Dma::port->CH [Channel].SRCADDR = reinterpret_cast <uint32_t >(helper.data ) + helper.transferred_size ;
258- }
259- else {
260- Dma::port->CH [Channel].DESTADDR = reinterpret_cast <uint32_t >(helper.data ) + helper.transferred_size ;
234+ // get the control register for the current channel
235+ const uint32_t control = Dma::port->CH [Channel].CONTROL ;
236+
237+ // check if we need to move to the next address
238+ if constexpr (Increment) {
239+ if (control & (0x1 << 26 )) {
240+ // advance by the source transfer width
241+ Dma::port->CH [Channel].SRCADDR = Dma::port->CH [Channel].SRCADDR + (1u << ((control >> 18 ) & 0x7 ));
242+ }
243+ if (control & (0x1 << 27 )) {
244+ // advance by the destination transfer width
245+ Dma::port->CH [Channel].DESTADDR = Dma::port->CH [Channel].DESTADDR + (1u << ((control >> 21 ) & 0x7 ));
246+ }
261247 }
262248
263249 // set the amount of data we will transfer
264- Dma::port->CH [Channel].CONTROL = (Dma::port-> CH [Channel]. CONTROL & (~0xfff )) | current_transfer;
250+ Dma::port->CH [Channel].CONTROL = (control & (~0xfff )) | current_transfer;
265251
266- // check if we need a irq after the current
267- if (!needs_irq) [[unlikely]] {
268- // clear the helper items
269- helper.data = nullptr ;
270- }
271- else {
272- helper.transferred_size += 0xfff ;
273- }
252+ // add the amount we are transferring right now
253+ helper.transferred_size += current_transfer;
274254
275255 // enable the channel
276256 Dma::port->CH [Channel].CONFIG |= 0x1 ;
@@ -318,15 +298,17 @@ namespace klib::core::lpc17xx::io {
318298 static_assert (!std::is_same_v<Destination, klib::io::dma::memory>, " Destination needs to be a peripheral for this function" );
319299
320300 // get the amount of bytes we need to transmit
321- const uint32_t size = source.size_bytes ();
301+ const uint32_t size = (
302+ source.size_bytes () / klib::min (sizeof (T), sizeof (uint32_t ))
303+ );
322304
323305 // set the dma destination
324306 Dma::port->CH [Channel].DESTADDR = reinterpret_cast <uint32_t >(Destination::template dma_data<0 >());
307+ Dma::port->CH [Channel].SRCADDR = reinterpret_cast <uint32_t >(source.data ());
325308
326309 // update the helper data with the information about the transfer
327310 // we know we are not writing to it so we can remove the const here
328311 // for the helper data
329- helper.data = const_cast <uint8_t *>(reinterpret_cast <const uint8_t *>(source.data ()));
330312 helper.requested_size = size;
331313 helper.transferred_size = 0x00 ;
332314 helper.callback = callback;
@@ -335,7 +317,7 @@ namespace klib::core::lpc17xx::io {
335317 Dma::port->CH [Channel].CONTROL = (
336318 (detail::dma::get_memory_burst_size (size) << 12 ) |
337319 (detail::dma::get_peripheral_burst_size (Destination::template dma_burst_size<0 >()) << 15 ) |
338- (detail::dma::get_transfer_width (sizeof (T)) << 18 ) |
320+ (detail::dma::get_transfer_width (klib::min ( sizeof (T), sizeof ( uint32_t ) )) << 18 ) |
339321 (detail::dma::get_transfer_width (Destination::template dma_width<0 >()) << 21 ) |
340322 (Destination::template dma_increment<0 >() << 27 ) |
341323 (MemoryIncrement << 26 ) | (0x1 << 31 )
@@ -357,7 +339,7 @@ namespace klib::core::lpc17xx::io {
357339 );
358340
359341 // start the transfer
360- peripheral_memory_impl<true >();
342+ peripheral_memory_impl<false >();
361343 }
362344
363345 /* *
@@ -369,18 +351,20 @@ namespace klib::core::lpc17xx::io {
369351 * @param size
370352 */
371353 template <bool MemoryIncrement = true , typename T>
372- static void read (const std::span<T>& destination, const detail::dma::interrupt_callback callback = nullptr ) {
354+ static void read (const std::span<T>& destination, const detail::dma::interrupt_callback callback = nullptr ) requires (!std::is_const_v<T>) {
373355 static_assert (!std::is_same_v<Source, klib::io::dma::memory>, " Source needs to be a peripheral for this function" );
374356 static_assert (std::is_same_v<Destination, klib::io::dma::memory>, " Destination needs to be memory for this function" );
375357
376- // get the amount of bytes we need to transmit
377- const uint32_t size = destination.size_bytes ();
358+ // get the amount of bytes we need to receive
359+ const uint32_t size = (
360+ destination.size_bytes () / klib::min (Source::template dma_width<1 >(), sizeof (uint32_t ))
361+ );
378362
379363 // set the source and destination
380364 Dma::port->CH [Channel].SRCADDR = reinterpret_cast <uint32_t >(Source::template dma_data<1 >());
365+ Dma::port->CH [Channel].DESTADDR = reinterpret_cast <uint32_t >(destination.data ());
381366
382367 // update the helper data with the information about the transfer
383- helper.data = reinterpret_cast <uint8_t *>(destination.data ());
384368 helper.requested_size = size;
385369 helper.transferred_size = 0x00 ;
386370 helper.callback = callback;
@@ -390,7 +374,7 @@ namespace klib::core::lpc17xx::io {
390374 (detail::dma::get_peripheral_burst_size (Source::template dma_burst_size<1 >()) << 12 ) |
391375 (detail::dma::get_memory_burst_size (size) << 15 ) |
392376 (detail::dma::get_transfer_width (Source::template dma_width<1 >()) << 18 ) |
393- (detail::dma::get_transfer_width (sizeof (T)) << 21 ) |
377+ (detail::dma::get_transfer_width (klib::min ( sizeof (T), sizeof ( uint32_t ) )) << 21 ) |
394378 (Source::template dma_increment<1 >() << 26 ) |
395379 (MemoryIncrement << 27 ) | (0x1 << 31 )
396380 );
@@ -422,10 +406,53 @@ namespace klib::core::lpc17xx::io {
422406 * @param destination
423407 * @param size
424408 */
425- template <bool MemoryIncrement = true >
426- static void transfer (const uint8_t * const source, uint8_t * const destination, uint16_t size ) {
409+ template <bool SourceMemoryIncrement = true , bool DestinationMemoryIncrement = true , typename T, typename G >
410+ static void transfer (const std::span<T>& source, const std::span<G>& destination, const detail::dma::interrupt_callback callback = nullptr ) requires (!std::is_const_v<G> ) {
427411 static_assert (std::is_same_v<Source, klib::io::dma::memory>, " Source needs to be memory for this function" );
428412 static_assert (std::is_same_v<Destination, klib::io::dma::memory>, " Destination needs to be memory for this function" );
413+
414+ // get the amount of bytes we need to move
415+ const uint32_t size = (
416+ klib::min (source.size_bytes (), destination.size_bytes ()) / klib::min (sizeof (T), sizeof (uint32_t ))
417+ );
418+
419+ // set the dma destination and source
420+ Dma::port->CH [Channel].DESTADDR = reinterpret_cast <uint32_t >(destination.data ());
421+ Dma::port->CH [Channel].SRCADDR = reinterpret_cast <uint32_t >(source.data ());
422+
423+ // update the helper data with the information about the transfer
424+ helper.requested_size = size;
425+ helper.transferred_size = 0x00 ;
426+ helper.callback = callback;
427+
428+ // setup the control register for the transfer
429+ Dma::port->CH [Channel].CONTROL = (
430+ (detail::dma::get_memory_burst_size (size) << 12 ) |
431+ (detail::dma::get_memory_burst_size (size) << 15 ) |
432+ (detail::dma::get_transfer_width (klib::min (sizeof (T), sizeof (uint32_t ))) << 18 ) |
433+ (detail::dma::get_transfer_width (klib::min (sizeof (T), sizeof (uint32_t ))) << 21 ) |
434+ (SourceMemoryIncrement << 26 ) |
435+ (DestinationMemoryIncrement << 27 ) |
436+ (0x1 << 31 )
437+ );
438+
439+ // check if we need a interrupt
440+ const bool irq = (size > 0xfff ) || (callback != nullptr );
441+
442+ // if we are enabling the interrupt make sure we clear the previous flags
443+ // to prevent a interrupt from triggering straight after enabling it
444+ if (irq) [[likely]] {
445+ Dma::port->INTTCCLEAR = 0x1 << Channel;
446+ }
447+
448+ // setup the channel
449+ Dma::port->CH [Channel].CONFIG = (
450+ (irq << 15 ) |
451+ (static_cast <uint32_t >(detail::dma::transfer_type::memory_to_memory) << 11 )
452+ );
453+
454+ // start the transfer
455+ peripheral_memory_impl<false >();
429456 }
430457
431458 /* *
@@ -448,7 +475,11 @@ namespace klib::core::lpc17xx::io {
448475 const uint32_t config = Dma::port->CH [Channel].CONFIG ;
449476
450477 // return if the enabled or active flag is set
451- return (config & 0x1 ) | (config & (0x1 << 17 )) | (helper.data != nullptr );
478+ return (
479+ (config & 0x1 ) | (config & (0x1 << 17 )) |
480+ (helper.callback != nullptr ) |
481+ (helper.transferred_size < helper.requested_size )
482+ );
452483 }
453484
454485 /* *
0 commit comments