Kitsok 0 10 марта, 2010 Опубликовано 10 марта, 2010 · Жалоба Добрый день! FreeRTOS завел, даже думал написать краткий мануал, а потом понял, что мануал давно написан и называется FreeRTOS Porting Guide, zltigo хоть и суров, но прав на 100% ;) Теперь взялся за ADC. Последовательность такая: прочитал User Manual, посмотрел исходники для gcc, посмотрел библиотеку NXP (LPC CDL), подключил ее. Причина использования библиотеки - любовь к функциям типа PINSEL_Set, оставшаяся от писания под SAM7S. Итого получилось так: void xSetupADC(void) { // Select pin that used as ADC function PINSEL_Set (PORT_0, 23, FUNC_1); PINSEL_Set (PORT_0, 24, FUNC_1); PINSEL_Set (PORT_0, 25, FUNC_1); PINSEL_Set (PORT_0, 26, FUNC_1); PINSEL_Set (PORT_1, 30, FUNC_3); PINSEL_Set (PORT_1, 31, FUNC_3); PINSEL_SetResistorMode(PORT_0,23,PINMODE_TRISTATE); PINSEL_SetResistorMode(PORT_0,24,PINMODE_TRISTATE); PINSEL_SetResistorMode(PORT_0,25,PINMODE_TRISTATE); PINSEL_SetResistorMode(PORT_0,26,PINMODE_TRISTATE); PINSEL_SetResistorMode(PORT_1,30,PINMODE_TRISTATE); PINSEL_SetResistorMode(PORT_1,31,PINMODE_TRISTATE); /* Init ADC device */ if ((adcdev = ADC_Init()) == 0) { while(1); } // Install ADC interrupt handler if ((VIC_InstallIRQ (ADC0_INT, (void *) ADC_ISR, 0x0F)) == _ERROR) { while(1); } // Set call back function for ADC //ADC_SetCBS (adcdev, (void *)usr_adc_cbs); // Configure ADC with 1MHz of freq, 10-bit of resolution ADC_Config (adcdev, 500000, 10); // Enable all channels ADC_EnableCH (adcdev, 0); ADC_EnableCH (adcdev, 1); ADC_EnableCH (adcdev, 2); ADC_EnableCH (adcdev, 3); ADC_EnableCH (adcdev, 4); ADC_EnableCH (adcdev, 5); // Enable interrupt for ADC0 channel 5 ADC_EnableInt (adcdev, 5); //ADC_EnableGlobalInt(adcdev); // Enable ADC interrupt source VIC_EnableInt (ADC0_INT); // Start ADC conversion ADC_Start (adcdev, ADC_START_CONTINUOUS, 0); } ADC_Config пришлось подправить, ибо частоту я выставляю не через библиотечные функции: S32 ADC_Config (S32 ADCdev, U32 freq, U32 resolution) { ADC_CFG_T *pADCdev = (ADC_CFG_T *) ADCdev; U32 tmp; if (pADCdev->init == FALSE) { return _ERROR; } if ((resolution > 10) || (resolution < 3)) { return _ERROR; } if (freq > 4500000) { return _ERROR; } tmp = SCB_GetPCLK (PCLK_ADC); //tmp = (tmp / freq) - 1; tmp = (30000000 / freq) -1; pADCdev->regptr->CR &= ~(ADC_CR_CLKDIV(0xFF)); pADCdev->regptr->CR |= ADC_CR_CLKDIV(tmp); pADCdev->regptr->CR &= ~(ADC_CR_BITS(3)); pADCdev->regptr->CR |= ADC_CR_BITS(resolution); return _NO_ERROR; } Обработчик прерывания: __irq __arm void ADC_ISR (void) { //FIXME For debug U32 regval;//= adccfg.regptr->STAT; //FIXME For debug volatile U32 ulStatus = AD0STAT; volatile U32 dummy; U8 i; regval = ulStatus; if (regval & 0x0000FF00) /* check OVERRUN error first */ { regval = ADC_STAT_CH_OVERRUN_FLAG(regval); //regval = AD0STAT; // BUGBUG There are 6 channels, not 8 for (i = 0; i < 6; i++) { if (regval & 0x01) { /* if overrun, just read ADDR to clear */ dummy = adccfg.regptr->DR[i]; } regval = regval >> 1; } } // Check DONE bit else if (regval & ADC_STAT_INT_FLAG) { regval = ADC_STAT_CH_DONE_FLAG(regval); // BUGBUG There are 6 channels, not 8 for (i = 0; i < 6; i++) { if (regval & 0x01) { /* if overrun, just read ADDR to clear */ adccfg.ADCBuff[i] = adccfg.regptr->DR[i]; } regval = regval >> 1; } } // call callback function if it is already installed if (adccfg.cbs != NULL) { adccfg.cbs(); } if ((ulStatus & 0x3f) != 0x3f) ulStatus=0; // Acknowledge interrupt VIC_Ack(); } Чего хотел добиться: 1. Чтобы работали все 6 каналов. 2. Чтобы работало в Free run в Burst-режиме 3. Чтобы возникало одно прерывание при отработке всех 6 каналов. 4. Прерывание поставлено на 5 канал, потому что он должен отработаться последним: The first conversion after the start corresponds to the least-significant 1 in the SEL field, then higher numbered 1 bits (pins) if applicable. В общем, ставлю я два брейка - один на VIC_Ack(), другой - на ulStatus=0, запускаю. Дальше что-то, что я не понимаю. Если стоит два брейка, то остановка происходит только на VIC_Ack(), и статусный регистр содержит 0x00013F3F, что более или менее соответствует ожиданиям. Не соответствует Overrun, происхождение которого я не понимаю. Но стоит снять брейк с VIC_Ack(), начинает срабатывать брейк на ulStatus=0, при этом ulStatus == 0x00013C3C, т.е. каналы 0 и 1 не отработали. Частоту АЦМ пробовал менять, история повторяется от 4.5МГц до 30кГц. Вопрос традиционный: что я делаю не так? Заранее спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kitsok 0 11 марта, 2010 Опубликовано 11 марта, 2010 · Жалоба Ну раз никто не знает, то сам расскажу ;) Во-первых, на моей отладочной плате (SK-MLPC2368) не был заведен Vref, и это раз. Во-вторых, я передумал вообще смотреть на статус каналов, и теперь в обработчике делаю так: U32 regval;//= adccfg.regptr->STAT; volatile U32 ulStatus = AD0STAT; volatile U32 dummy; U8 i; regval = ulStatus; for(i=0;i<6;i++) { /* Read ADC value */ dummy=adccfg.regptr->DR[i]; /* Cut to 10 bits */ dummy = ( dummy >>6 ) & 0x3ff; /* Add data to accumulator */ ulADC_RawBuf[i] += dummy; } /* Oversampling counter */ ulCnt++; if (ulCnt == 128) { /* Copy data to global buffer */ for(i=0;i<6;i++) { /* Copy data to global buffer and divide it by 2 */ *(ptrADC_Buf+i) = (ulADC_RawBuf[i]>>1); /* Reset raw buffer */ ulADC_RawBuf[i]=0; } /* Reset oversampling counter */ ulCnt=0; } Все вполне кошерно за исключением того, что 1023*64 никак не равно 65535, но в моем применении это - всё равно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 11 марта, 2010 Опубликовано 11 марта, 2010 · Жалоба Причина использования библиотеки - любовь к функциям типа PINSEL_Set, оставшаяся от писания под SAM7S. Даже помыслить не мог, что для этого требуется какая-то "библиотека" :( #define PX( x, y ) ( ((unsigned long)((y)&0x3))<<(((x)&0xF)<<1) ) #define PINSEL( x, y, z ) (x) = ( ( (x)&( ~PX( (y), 0x3 ) ) )|PX( (y), (z) ) ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kitsok 0 11 марта, 2010 Опубликовано 11 марта, 2010 · Жалоба В библиотэке оно выглядит так: void PINSEL_Set ( U32 portnum, U32 pinnum, U32 funcnum) { U32 pinnum_t = pinnum; U32 pinselreg_idx = 2 * portnum; if (pinnum_t >= 16) { pinnum_t -= 16; pinselreg_idx++; } PINSEL->PINSELn[pinselreg_idx] &= ~((U32)(3 << (pinnum_t * 2))); PINSEL->PINSELn[pinselreg_idx] |= (U32)(funcnum << (pinnum_t * 2)); } Я занялся чисткой кода, библиотека - библиотекой, но мне оно на дефайнах нравится много больше, поэтому для освоенной части как раз такие дефайны и пишу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 11 марта, 2010 Опубликовано 11 марта, 2010 · Жалоба В библиотэке оно выглядит так: Не удивили :( обычный мрачный бред в стиле "я программировать не умею", только почему-то распространяемая публично :(, причем, если я Вас правильно понял, и, что что убивает наповал :( :( - ПРОИЗВОДИТЕЛЕМ! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kitsok 0 12 марта, 2010 Опубликовано 12 марта, 2010 · Жалоба причем, если я Вас правильно понял, и, что что убивает наповал :( :( - ПРОИЗВОДИТЕЛЕМ! Да, это вполне себе Филипсовская библиотека. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться