Создание собственной системы стабилизации

rual
SergDoc:

но счтитаю что усб надо бы оттуда прикрутить, нету ничего лишнего практически…

Ну да, бегло пробежался по коду, вроде всё есть в одном файле, надо только библиотечные прикрутить.

Razek
SergDoc:

да всё через усб, но я уже писал выше,

А у них свой бут лоадер или встроеный юзают?

SergDoc

Встроеный, я проверял всё работает 😃

okan_vitaliy

Есть проблема с приоритетом уарта. При отключенном обмене время цикла четко 3000мкс. При включенном обмене с компьютером. Время обмена доходит до 22мс. Данные не от балды - мерял осциком. Так что при полетах с телеметрией подключенной к вингуи могут быть траблы с коптером.
ps. Короче время цикла может меняться от 2мс до 22мс.

SergDoc
okan_vitaliy:

Время обмена доходит до 22мс.

время обмена или цикла? обмен как-то всё равно, а цикл не меняется от уарта - ну я по крайней мере не заметил…
и приоритет не высокий

// DMA TX Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
okan_vitaliy

Именно время цикла увеличивается до 22мс. Короче получается афигенная задержка и мы теряем выборки.(смотреть нужно осциком а не гуи. гуи показывает стабильное время.) Кольцо то у нас не в прерываниях работает, и вот приходящее прерывание по обработке обмена прерывает основной цикл. А это не есть гуд. Короче мне так кажется - нужно loop садить куда нибудь в прерывание. И приоритет этого прерывания делать самый высокий, ну кроме конечно системного таймера.

SergDoc

и куда это ткнуть осцылл, чтобы цикл померять?

okan_vitaliy

loopTime = currentTime + mcfg.looptime;
computeIMU();
LED2_TOGGLE;
// Measure loop rate just afer reading the sensors
currentTime = micros();
cycleTime = (int32_t)(currentTime - previousTime);
previousTime = currentTime;

и мерять на светодиоде.

mataor

хм… если в программе время цикла неизменно а в реальности меняется - значит у вас приоритет системного времени низкий + на что-то уходит сильно много времени в обработчике уарта (хотя на что там времени тратится - по готовности засунуть байт в уарт и спать до следующего).
ради интереса сегодня-завтра посмотрю что у меня творится

SergDoc

Я тоже думаю что причина не в УАРТЕ, и время цикла правильное что приходит на ум 22милисекунды - какой-то баг по гире? системное время в высшем приоритете!

да и первый уарт работает на прямую с памятью, не отвлекая жирный проц 😃 - как бы не разленился 😃

SergDoc

ну да как-то дороговато 😦 хотя если посмотреть иму платы от тех же виртуалроботикс (мультипилот) то цена приемлимая…

Sir_Alex

Плата дорогая, 5983 и 5883 практически не отличаются по цене, не понятно с чего бы этой платке стоить дороже того же CRIUS’a (или других контроллеров, коих сейчас полно)

З.Ы. 5983 можно прикупть на eBay баксов за 7
З.Ы.Ы. VRBrain такая же дорогая поделка как и PX4 - не вижу смысла переплачивать за такие девайсы.

SergDoc
Sir_Alex:

З.Ы.Ы. VRBrain такая же дорогая поделка как и PX4 - не вижу смысла переплачивать за такие девайсы.

ну как бэ плата то есть конкурентная и явно дешевле 😃 а вот 5983 можно повесить на свободный spi (это в текущей версии), а 5883 можно и отключать программно или заменить вроде подключение одинаковое если по i2c…
и похоже развод это, зачем 5983 цеплять по i2c да пусть к той же mpu?

okan_vitaliy
SergDoc:

Я тоже думаю что причина не в УАРТЕ, и время цикла правильное что приходит на ум 22милисекунды - какой-то баг по гире? системное время в высшем приоритете!

да и первый уарт работает на прямую с памятью, не отвлекая жирный проц 😃 - как бы не разленился 😃

Вот тут делаю измерение-
LED3_ON;
serialCom();
LED3_OFF;
Измеряю время работы функции обмена. Меряем на светодиоде. Когда происходит чтение реальных данных из гуи, то имеем время 19мс. А обработка обмена у нас висит как раз в основном цикле. Частота этих багов соответствует частоте опроса из гуи. Интересно что б кто нибудь проверил. Проверять только в режиме чтения реальных данных в вингуи или в мультивий-конфигураторе.

SergDoc

this code is executed at each loop and won’t interfere with control loop if it lasts less than 650 microseconds

т.е. если бы оно тормозило цикл это было бы видно в гуи, и уж у Таймкопа аппараты точно падали при подключении к гуи, да и вий бы никуда не полетел, хотя если мы допустим из 400, расчётов потеряем даже 60% -70% ничего не случится, скоро предоставится возможность всё перепроверить - проверю обязательно… сейчас тупо лень с аппарата плату снимать 😃

okan_vitaliy
SergDoc:

т.е. если бы оно тормозило цикл это было бы видно в гуи, и уж у Таймкопа аппараты точно падали при подключении к гуи, да и вий бы никуда не полетел, хотя если мы допустим из 400, расчётов потеряем даже 60% -70% ничего не случится, скоро предоставится возможность всё перепроверить - проверю обязательно… сейчас тупо лень с аппарата плату снимать 😃

Таймкоп не причем помойму.
Вот тут проблемка
void uartWrite( uint8_t ch)
{
LED3_ON;
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
};
LED3_OFF;
txBuffer[txBufferHead] = ch;

Цикл ожидания равен примерно 87 мкс. И это на каждом байте. Можете прикинуть тормоза системы при усиленном обмене. Тут чето с дма не то.

mataor

хех… ну как я и говорил - проблемка в уарте, а не в функции serialcom

SergDoc

если его убрать УАРТ вешается, или отказываться от ДМА или добивать этот чёртов уарт, по всей видимости переполняется буфер ДМА ибо пихаем слишком быстро в него, я как и писал выше воткнул этот костыль, ибо не нашел ошибку, при этом уарт на приём работает, а на выдачу затыкается,
первая версия была такая:

// Receive buffer, circular DMA
volatile uint8_t rxBuffer[UART_BUFFER_SIZE];
uint32_t rxDMAPos = 0;
volatile uint8_t txBuffer[UART_BUFFER_SIZE];
uint32_t txBufferTail = 0;
uint32_t txBufferHead = 0;


static void uartTxDMA(void)
{
    DMA2_Stream7->M0AR = (uint32_t)&txBuffer[txBufferTail];
    if (txBufferHead > txBufferTail) {
        DMA_SetCurrDataCounter(DMA2_Stream7, txBufferHead - txBufferTail);//DMA2_Stream7->NDTR = txBufferHead - txBufferTail;
        txBufferTail = txBufferHead;
    } else {
        DMA_SetCurrDataCounter(DMA2_Stream7, UART_BUFFER_SIZE - txBufferTail);//DMA2_Stream7->NDTR = UART_BUFFER_SIZE - txBufferTail;
        txBufferTail = 0;
    }


    DMA_Cmd(DMA2_Stream7, ENABLE);
}


void DMA2_Stream7_IRQHandler(void)
{


    if(DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7))
           {
                        DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);


                        DMA_Cmd(DMA2_Stream7, DISABLE);
                     }


    if (txBufferHead != txBufferTail)
        uartTxDMA();
}


void uartInit(uint32_t speed)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;



        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        // USART1_TX    PA9
    // USART1_RX    PA10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
      GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);








    // DMA TX Interrupt
        /* Configure the Priority Group to 2 bits */
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);




        RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 , ENABLE);
    USART_InitStructure.USART_BaudRate = speed;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);




        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    // Receive DMA into a circular buffer
    DMA_DeInit(DMA2_Stream5);//
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;//
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rxBuffer;//
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//
    DMA_InitStructure.DMA_BufferSize = UART_BUFFER_SIZE;//
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//
    DMA_Init(DMA2_Stream5, &DMA_InitStructure);//
    DMA_Cmd(DMA2_Stream5, ENABLE);//
    /* Enable the USART Rx DMA request */
        USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
    rxDMAPos = DMA_GetCurrDataCounter(DMA2_Stream5);







    // Transmit DMA
    DMA_DeInit(DMA2_Stream7);
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
      DMA_InitStructure.DMA_FIFOMode =DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;








        DMA_Init(DMA2_Stream7, &DMA_InitStructure);





        DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);


        DMA_SetCurrDataCounter(DMA2_Stream7, 0);//DMA2_Stream7->NDTR = 0;


        USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);


        USART_Cmd(USART1, ENABLE);
}


uint16_t uartAvailable(void)
{
    return (DMA_GetCurrDataCounter(DMA2_Stream5) != rxDMAPos) ? true : false;
}


bool uartTransmitEmpty(void)
{
    return (txBufferTail == txBufferHead);
}


uint8_t uartRead(void)
{
    uint8_t ch;


    ch = rxBuffer[UART_BUFFER_SIZE - rxDMAPos];
    // go back around the buffer
    if (--rxDMAPos == 0)
        rxDMAPos = UART_BUFFER_SIZE;


    return ch;
}


uint8_t uartReadPoll(void)
{
    while (!uartAvailable()); // wait for some bytes
    return uartRead();
}


void uartWrite(uint8_t ch)
{
    txBuffer[txBufferHead] = ch;
    txBufferHead = (txBufferHead + 1) % UART_BUFFER_SIZE;


    // if DMA wasn't enabled, fire it up
    if (DMA_GetCmdStatus(DMA2_Stream7) == DISABLE)//(!(DMA2_Stream7->CR & 1))


        uartTxDMA();
}


void uartPrint(char *str)
{
    while (*str)
        uartWrite(*(str++));
}

она вешалась:(

может сделать так:

void uartWrite(uint8_t ch)
// if DMA wasn't enabled, fire it up
{
if (!(DMA2_Stream7->CR & 1)) {
txBuffer[txBufferHead] = ch;

txBufferHead = (txBufferHead + 1) % UART_BUFFER_SIZE;

uartTxDMA();
}
}
rual
okan_vitaliy:

void uartWrite( uint8_t ch)
{
LED3_ON;
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
};
LED3_OFF;
txBuffer[txBufferHead] = ch;

Цикл ожидания равен примерно 87 мкс. И это на каждом байте. Можете прикинуть тормоза системы при усиленном обмене. Тут чето с дма не то.

Верно, это косяк! Смысл использования ПДП как раз в том чтобы ничего не ждать! uartWrite должна вычислять хвост буфера ПДП и класть символ в [ХВОСТ+1], и увеличивать счетчик ПДП на один. Если ХВОСТ+1 упирается в конец буфера, то возвращать признак переполнения, по нему пропускать вывод в порт, либо ждать завершения с циклом счёта. А ещё лучше сделать кольцевой буфер и при записи писать по кругу, и только если догнал хвост возвращать переполнение. Важно перед операциями с регистрами ПДП запрещать запрос канала.

mataor

кстати такой вопрос…
а в чем глобальный смысл использовать ДМА для уарта?
разницу в использовании процессора наврятли заметим - уарт работает без участия ЦПУ, а по времени засунуть байт в уарт или в ДМА -> уарт думаю что разницы не будет.

единственная разница будет в том случае, если ДМА будем передавать весь буфер целиком.

так что без переработки этого участка плюсов в ДМА не вижу.