ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
19 апреля
672581 Топик полностью
VVB (05.05.2016 12:29 - 15:26, просмотров: 299) ответил Звероящер на Всё заработало. Было, как всегда, всё просто. По привычке в ИАРе проект для плюсов сварганил, ну и сишные и асмовые фиче не работали. Переставил крыжик в компилере на "Си" и всё поехало. Ладно, буду теперь думать как к плюсам прерывания прикрутить.
Подброшу:  enum IRQnumber { IRQ_ADC1Group1 = 15, IRQ_CAN1level0 = 16, IRQ_HET1level2 = 24, IRQ_MibSPI1level1 = 26, IRQ_CAN1level1 = 29, IRQ_CAN2level0 = 35, IRQ_MibSPI3level1 = 38, IRQ_CAN2level1 = 42, IRQ_CAN1IF3 = 44, IRQ_CAN3level0 = 45, IRQ_CAN2IF3 = 46, IRQ_CAN3level1 = 55, IRQ_MibSPI5level1 = 56, IRQ_CAN3IF3 = 60, IRQ_I2C = 66, IRQ_HET2level2 = 73, }; enum IRQtype {IRQ = 0, FIQ = 1}; class irq_capable { public: irq_capable(IRQnumber irqnumber, IRQtype irqtype); virtual bool handlerIRQ() = 0; virtual ~irq_capable(); }; namespace test { void emulateIRQ(IRQnumber n); } /* namespace test */ namespace { irq_capable *registeredObjects[VIM_CHANNELS] = {nullptr}; bool callISR(IRQnumber n) {return registeredObjects[n]->handlerIRQ();} void adc1Group1Interrupt() ; void can1Level0Interrupt() ; void het1Level2Interrupt() ; void mibspi1Level1Interrupt() ; void can1Level1Interrupt() ; void can2Level0Interrupt() ; void mibspi3Level1Interrupt() ; void can2Level1Interrupt() ; void can1IF3Interrupt() ; void can3Level0Interrupt() ; void can2IF3Interrupt() ; void can3Level1Interrupt() ; void mibspi5Level1Interrupt() ; void can3IF3Interrupt() ; void i2cInterrupt() ; void het2Level2Interrupt() ; void adc1Group1Interrupt() {callISR(IRQ_ADC1Group1);} void can1Level0Interrupt() {callISR(IRQ_CAN1level0);} void het1Level2Interrupt() {callISR(IRQ_HET1level2);} void mibspi1Level1Interrupt() {callISR(IRQ_MibSPI1level1);} void can1Level1Interrupt() {callISR(IRQ_CAN1level1);} void can2Level0Interrupt() {callISR(IRQ_CAN2level0);} void mibspi3Level1Interrupt() {callISR(IRQ_MibSPI3level1);} void can2Level1Interrupt() {callISR(IRQ_CAN2level1);} void can1IF3Interrupt() {callISR(IRQ_CAN1IF3);} void can3Level0Interrupt() {callISR(IRQ_CAN3level0);} void can2IF3Interrupt() {callISR(IRQ_CAN2IF3);} void can3Level1Interrupt() {callISR(IRQ_CAN3level1);} void mibspi5Level1Interrupt() {callISR(IRQ_MibSPI5level1);} void can3IF3Interrupt() {callISR(IRQ_CAN3IF3);} void i2cInterrupt() {callISR(IRQ_I2C);} void het2Level2Interrupt() {callISR(IRQ_HET2level2);} typedef void (*voidfunc)(); voidfunc getVectorFromIRQnumber(IRQnumber n) { switch (n) { case IRQ_ADC1Group1: return adc1Group1Interrupt; case IRQ_CAN1level0: return can1Level0Interrupt; case IRQ_HET1level2: return het1Level2Interrupt; case IRQ_MibSPI1level1: return mibspi1Level1Interrupt; case IRQ_CAN1level1: return can1Level1Interrupt; case IRQ_CAN2level0: return can2Level0Interrupt; case IRQ_MibSPI3level1: return mibspi3Level1Interrupt; case IRQ_CAN2level1: return can2Level1Interrupt; case IRQ_CAN1IF3: return can1IF3Interrupt; case IRQ_CAN3level0: return can3Level0Interrupt; case IRQ_CAN2IF3: return can2IF3Interrupt; case IRQ_CAN3level1: return can3Level1Interrupt; case IRQ_MibSPI5level1: return mibspi5Level1Interrupt; case IRQ_CAN3IF3: return can3IF3Interrupt; case IRQ_I2C: return i2cInterrupt; case IRQ_HET2level2: return het2Level2Interrupt; default: throw exc("Unknown handler for given IRQ number in irq::<anonymous>::getVectorFromIRQnumber"); } } } /* anonymous namespace */ irq_capable::irq_capable(IRQnumber irqNumber, IRQtype irqtype) { if (registeredObjects[irqNumber]) { throw exc("IRQ is already registered"); } registeredObjects[irqNumber] = this; const voidfunc handler = getVectorFromIRQnumber(irqNumber); if (IRQ == irqtype) { registerIRQvectorInVIM(irqNumber, handler); } else { registerFIQvectorInVIM(irqNumber, handler); } } irq_capable::~irq_capable() { size_t idx = 0; while (registeredObjects[idx] != this) { ++idx; } registeredObjects[idx] = nullptr; } namespace test { void emulateIRQ(IRQnumber n) { registeredObjects[n]->handlerIRQ(); } } /* namespace test */ Пример использования: namespace { class iadc : private irq::irq_capable { volatile adcBase& adc; uint32_t *ram; void acknowledgeIRQforGroup1(); uint32_t getDataFromRAM(uint32_t offset); void init(); void enableGroup1ConversationCompleteIRQ(); void startGroup1ConversationForAllChannes(); void operator=(const iadc& ); iadc(const iadc& ); virtual bool handlerIRQ() override; public: iadc(volatile adcBase& adc, uint32_t *ram); virtual ~iadc(){} }; iadc::iadc(volatile adcBase &adc, uint32_t *ram) : irq_capable(irq::IRQ_ADC1Group1, irq::IRQ), adc(adc), ram(ram) { init(); enableGroup1ConversationCompleteIRQ(); for (size_t i = 0; i < maxChannels; ++i) convertHandlers[i].physObjectHanler = nullptr; startGroup1ConversationForAllChannes(); } /* * Обработчик IRQ по завершению преобразования */ bool iadc::handlerIRQ() { acknowledgeIRQforGroup1(); for (size_t i = 0; i < maxChannels; ++i) { ADCdata[i] = getDataFromRAM(i); } return false; } } /* anonymous namespace */ void create(void *baseAddress, void *RAMaddress) { if (ptrIADC) { throw exc("Error in creating internal ADC: already created"); } ptrIADC = new iadc(*reinterpret_cast<volatile adcBase *>(baseAddress), reinterpret_cast<uint32_t *>(RAMaddress)); } Такой подход позволяет изолировать работу с прерываниями: конкретные вектора (жёстко прописанные в VIM) вызывают обработчики для тех объектов, которые зарегистрировали себя как источники прерываний. Легко эмулируется любое прерывание через вызов test::emulateIRQ(), что существенно облегчает тестирование и разработку с использованием TDD. Объекты, которые используют прерывания, могут быть полностью скрыты из глобального пространства имён; вектора прерываний также скрыты из глобального пространства, но имеется возможность эмуляции любого прерывания (я эту фишку использовал при тестировании рабочего кода на ПК). Но у меня Cortex-R4 и VIM, где я могу требуемые вектора прямо в регистры VIM загрузить, в отличие от Cortex-M, там придётся держать вектора в ОЗУ и адрес таблицы векторов указывать в соответствующем системном регистре. Да, кстати, такому коду абсолютно пофиг на режим работы: ARM или THUMB. Никаких дополнительных ключей компиляции использовать не надо.