Создание собственной системы стабилизации
но счтитаю что усб надо бы оттуда прикрутить, нету ничего лишнего практически…
Ну да, бегло пробежался по коду, вроде всё есть в одном файле, надо только библиотечные прикрутить.
да всё через усб, но я уже писал выше,
А у них свой бут лоадер или встроеный юзают?
Встроеный, я проверял всё работает 😃
Есть проблема с приоритетом уарта. При отключенном обмене время цикла четко 3000мкс. При включенном обмене с компьютером. Время обмена доходит до 22мс. Данные не от балды - мерял осциком. Так что при полетах с телеметрией подключенной к вингуи могут быть траблы с коптером.
ps. Короче время цикла может меняться от 2мс до 22мс.
Время обмена доходит до 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);
Именно время цикла увеличивается до 22мс. Короче получается афигенная задержка и мы теряем выборки.(смотреть нужно осциком а не гуи. гуи показывает стабильное время.) Кольцо то у нас не в прерываниях работает, и вот приходящее прерывание по обработке обмена прерывает основной цикл. А это не есть гуд. Короче мне так кажется - нужно loop садить куда нибудь в прерывание. И приоритет этого прерывания делать самый высокий, ну кроме конечно системного таймера.
и куда это ткнуть осцылл, чтобы цикл померять?
loopTime = currentTime + mcfg.looptime;
computeIMU();
LED2_TOGGLE;
// Measure loop rate just afer reading the sensors
currentTime = micros();
cycleTime = (int32_t)(currentTime - previousTime);
previousTime = currentTime;
и мерять на светодиоде.
хм… если в программе время цикла неизменно а в реальности меняется - значит у вас приоритет системного времени низкий + на что-то уходит сильно много времени в обработчике уарта (хотя на что там времени тратится - по готовности засунуть байт в уарт и спать до следующего).
ради интереса сегодня-завтра посмотрю что у меня творится
Я тоже думаю что причина не в УАРТЕ, и время цикла правильное что приходит на ум 22милисекунды - какой-то баг по гире? системное время в высшем приоритете!
да и первый уарт работает на прямую с памятью, не отвлекая жирный проц 😃 - как бы не разленился 😃
Ловите вкусняшку - 10DOF платка и никакого и2с - все по SPI можно подключить www.aliexpress.com/item/…/925324231.html
хотя дороговато немного)))
ну да как-то дороговато 😦 хотя если посмотреть иму платы от тех же виртуалроботикс (мультипилот) то цена приемлимая…
Плата дорогая, 5983 и 5883 практически не отличаются по цене, не понятно с чего бы этой платке стоить дороже того же CRIUS’a (или других контроллеров, коих сейчас полно)
З.Ы. 5983 можно прикупть на eBay баксов за 7
З.Ы.Ы. VRBrain такая же дорогая поделка как и PX4 - не вижу смысла переплачивать за такие девайсы.
З.Ы.Ы. VRBrain такая же дорогая поделка как и PX4 - не вижу смысла переплачивать за такие девайсы.
ну как бэ плата то есть конкурентная и явно дешевле 😃 а вот 5983 можно повесить на свободный spi (это в текущей версии), а 5883 можно и отключать программно или заменить вроде подключение одинаковое если по i2c…
и похоже развод это, зачем 5983 цеплять по i2c да пусть к той же mpu?
Я тоже думаю что причина не в УАРТЕ, и время цикла правильное что приходит на ум 22милисекунды - какой-то баг по гире? системное время в высшем приоритете!
да и первый уарт работает на прямую с памятью, не отвлекая жирный проц 😃 - как бы не разленился 😃
Вот тут делаю измерение-
LED3_ON;
serialCom();
LED3_OFF;
Измеряю время работы функции обмена. Меряем на светодиоде. Когда происходит чтение реальных данных из гуи, то имеем время 19мс. А обработка обмена у нас висит как раз в основном цикле. Частота этих багов соответствует частоте опроса из гуи. Интересно что б кто нибудь проверил. Проверять только в режиме чтения реальных данных в вингуи или в мультивий-конфигураторе.
this code is executed at each loop and won’t interfere with control loop if it lasts less than 650 microseconds
т.е. если бы оно тормозило цикл это было бы видно в гуи, и уж у Таймкопа аппараты точно падали при подключении к гуи, да и вий бы никуда не полетел, хотя если мы допустим из 400, расчётов потеряем даже 60% -70% ничего не случится, скоро предоставится возможность всё перепроверить - проверю обязательно… сейчас тупо лень с аппарата плату снимать 😃
т.е. если бы оно тормозило цикл это было бы видно в гуи, и уж у Таймкопа аппараты точно падали при подключении к гуи, да и вий бы никуда не полетел, хотя если мы допустим из 400, расчётов потеряем даже 60% -70% ничего не случится, скоро предоставится возможность всё перепроверить - проверю обязательно… сейчас тупо лень с аппарата плату снимать 😃
Таймкоп не причем помойму.
Вот тут проблемка
void uartWrite( uint8_t ch)
{
LED3_ON;
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
};
LED3_OFF;
txBuffer[txBufferHead] = ch;
Цикл ожидания равен примерно 87 мкс. И это на каждом байте. Можете прикинуть тормоза системы при усиленном обмене. Тут чето с дма не то.
хех… ну как я и говорил - проблемка в уарте, а не в функции serialcom
если его убрать УАРТ вешается, или отказываться от ДМА или добивать этот чёртов уарт, по всей видимости переполняется буфер ДМА ибо пихаем слишком быстро в него, я как и писал выше воткнул этот костыль, ибо не нашел ошибку, при этом уарт на приём работает, а на выдачу затыкается,
первая версия была такая:
// 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();
}
}
void uartWrite( uint8_t ch)
{
LED3_ON;
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE) {
};
LED3_OFF;
txBuffer[txBufferHead] = ch;Цикл ожидания равен примерно 87 мкс. И это на каждом байте. Можете прикинуть тормоза системы при усиленном обмене. Тут чето с дма не то.
Верно, это косяк! Смысл использования ПДП как раз в том чтобы ничего не ждать! uartWrite должна вычислять хвост буфера ПДП и класть символ в [ХВОСТ+1], и увеличивать счетчик ПДП на один. Если ХВОСТ+1 упирается в конец буфера, то возвращать признак переполнения, по нему пропускать вывод в порт, либо ждать завершения с циклом счёта. А ещё лучше сделать кольцевой буфер и при записи писать по кругу, и только если догнал хвост возвращать переполнение. Важно перед операциями с регистрами ПДП запрещать запрос канала.
кстати такой вопрос…
а в чем глобальный смысл использовать ДМА для уарта?
разницу в использовании процессора наврятли заметим - уарт работает без участия ЦПУ, а по времени засунуть байт в уарт или в ДМА -> уарт думаю что разницы не будет.
единственная разница будет в том случае, если ДМА будем передавать весь буфер целиком.
так что без переработки этого участка плюсов в ДМА не вижу.