/* * This file is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Code by Andrew Tridgell and Siddharth Bharat Purohit */ #include "shared_dma.h" /* code to handle sharing of DMA channels between peripherals */ #if CH_CFG_USE_SEMAPHORES == TRUE using namespace ChibiOS; extern const AP_HAL::HAL& hal; Shared_DMA::dma_lock Shared_DMA::locks[SHARED_DMA_MAX_STREAM_ID+1]; volatile Shared_DMA::dma_stats* Shared_DMA::_contention_stats; void Shared_DMA::init(void) { for (uint8_t i=0; icontention = true; if (_contention_stats != nullptr) { _contention_stats[stream_id1].contended_locks++; } } chSysEnable(); contention = true; return false; } if (_contention_stats != nullptr) { _contention_stats[stream_id1].uncontended_locks++; } if (!lock_stream_nonblocking(stream_id2)) { unlock_stream(stream_id1); chSysDisable(); if (locks[stream_id2].obj != nullptr && locks[stream_id2].obj != this) { locks[stream_id2].obj->contention = true; if (_contention_stats != nullptr) { _contention_stats[stream_id2].contended_locks++; } } chSysEnable(); contention = true; return false; } lock_core(); if (_contention_stats != nullptr) { _contention_stats[stream_id2].uncontended_locks++; } return true; } // unlock the DMA channels void Shared_DMA::unlock(void) { osalDbgAssert(have_lock, "must have lock"); unlock_stream(stream_id2); unlock_stream(stream_id1); have_lock = false; } // unlock the DMA channels from a lock zone void Shared_DMA::unlock_from_lockzone(void) { osalDbgAssert(have_lock, "must have lock"); if (stream_id2 < SHARED_DMA_MAX_STREAM_ID) { unlock_stream_from_IRQ(stream_id2); chSchRescheduleS(); } if (stream_id1 < SHARED_DMA_MAX_STREAM_ID) { unlock_stream_from_IRQ(stream_id1); chSchRescheduleS(); } have_lock = false; } // unlock the DMA channels from an IRQ void Shared_DMA::unlock_from_IRQ(void) { osalDbgAssert(have_lock, "must have lock"); unlock_stream_from_IRQ(stream_id2); unlock_stream_from_IRQ(stream_id1); have_lock = false; } /* lock all channels - used on reboot to ensure no sensor DMA is in progress */ void Shared_DMA::lock_all(void) { for (uint8_t i=0; isnprintf(buf, bufsize, "DMAV1\n"); if (n <= 0) { return 0; } buf += n; bufsize -= n; total += n; for (uint8_t i = 0; i < SHARED_DMA_MAX_STREAM_ID + 1; i++) { if (locks[i].obj == nullptr) { continue; } const char* fmt = "DMA=%1u STRM=%1u ULCK=%8u CLCK=%8u CONT=%4.1f%%\n"; float cond_per = 100.0f * float(_contention_stats[i].contended_locks) / (1 + _contention_stats[i].contended_locks + _contention_stats[i].uncontended_locks); n = hal.util->snprintf(buf, bufsize, fmt, i / 8 + 1, i % 8, _contention_stats[i].uncontended_locks, _contention_stats[i].contended_locks, cond_per); if (n <= 0) { break; } buf += n; bufsize -= n; total += n; _contention_stats[i].contended_locks = 0; _contention_stats[i].uncontended_locks = 0; } return total; } #endif // CH_CFG_USE_SEMAPHORES