Romziz
1

Проблема с большими массивами

30.07.2017, 02:09. Показов 9645. Ответов 65
Метки нет (Все метки)

Добрый день. Есть проблема с большими массивами, помогите пожалуйста.

Камень stm32f051k8t6 8кб озу, Eclipse

Проблема 1 - есть 2 массива по 1750 байт. Когда копирую значения из одного в другой, иногда происходят зависания. Меняешь имя массива и не виснет. Ставишь обратно - виснет. Не могу понять - почему такое может быть ? компилятор не ругается, памяти вроде хватает.

Проблема 2

Создаю массив вот так:
Код
#define buffers_len 1750
uint8_t buffer1[buffers_len];
заполняю массив байтами вот так:

Код
for(int i = 0 ; i<1700; i++) buffer1[i] = 0xBB;
Потом stm высылает этот пакет сначала по старинке через USORT1->TDR, потом через DMA на юарт. Все хорошо на выходе, байты одинаковые и равны 0xBB.

Создаю второй массив:
Код
 uint8_t buffer2[buffers_len];
Ничего с ним не делаю, он просто жрет память и все.

Начинаются чудеса.

В середине посылки у DMA появляются какие то левые байты штук 20. 2 посылки друг за другом - через USORT1-> TDR норм, через DMA какие то левые байты.

опять же, изменяю имя массива с buffer1 на buffer21 , глюки могут пропасть.

Переписал код, теперь с двумя большими массивами камень может зависнуть, когда DMA начнет передавать байты в юарт. Удаляю второй большой массив - все работает хорошо.

Предчувствую что лезет оно куда то не в свою область памяти или что то подобное. Но понять почему так - не могу.
Как будто памяти не хватает. Но компилятор не ругается. Или может быть под такие длинные массивы нет дефрагментированных участков. Или еще что то такое, чего я не знаю.

Может это какие то частые костыли, может кто то подскажет куда копать ? Буду благодарен любым советам.
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.07.2017, 02:09
Ответы с готовыми решениями:

dsPIC33E проблема с массивами
Привет всем. Такая проблема. Пытаюсь просто объявить массив unsykned int и МК dsPIC33EP256MU810...

CCS PIC проблема с массивами
В программе объявляю локально массив данных int8 data, проблема в том, что объявление массива...

Работа с большими массивами
Есть задача: получение санитарной зоны вокруг антенн, связи с особенностью решения задачи иного...

Работа с большими массивами
Бодрого дня. Есть ли какие секреты работы с большими массивами? Есть файл с 1.500.000 строк 1)...

65
Oxford
30.07.2017, 02:38 2
Под KEIL соберите проект, потестите.
0 / 0 / 0
Регистрация: 25.10.2013
Сообщений: 1
30.07.2017, 03:14 3
Надеюсь, массивы объявлены не в теле какой-то функции? Они точно глобальные?
Попробуйте отключить оптимизацию.
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 385
30.07.2017, 09:25 4
Посмотрите адреса, по которым массивы размещаются. Посмотрите браузер памяти.
0
0 / 0 / 0
Регистрация: 17.01.2016
Сообщений: 44
30.07.2017, 10:49 5
Цитата Сообщение от Romziz
Создаю второй массив:
Код:
uint8_t buffer2[buffers_len];
Ничего с ним не делаю, он просто жрет память и все.

Начинаются чудеса.
Возможно есть некий буффер, мимо которого ваша программа "промахивается" и до объявления второго массива эти "промахи" попадали в не занятую чем-либо память. Объявив второй массив вы заставили этот буффер "потесниться" подставив тем самым другие переменные под "промахи", которые их и портят. Сравните map-файлы для обоих случаев, прикиньте куда идёт несанкционированная запись, если сегмент не зануляется в стартапе - забейте его оттуда какими-нибудь 0xAA и после воспроизведения ошибки проверьте незанятые согласно map-файлу участки - если Нечто там наследило - точку прерывания на изменение данных по этим адресам. Забивать маской нужно до инициализации сегмента данных. :)
0
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
30.07.2017, 11:25 6
Попробую угадать :) USORT1->TDR 16 битный регистр , а uint8_t buffer2[buffers_len]; не выравнивается :) . PS с данным процом не работал .
0
Romziz
30.07.2017, 12:12 7
Спасибо всем за ответы.

Попробую уточнить:

1. Массивы объявлены глобально
2. А что такое браузер памяти ? Адреса посмотрел в map файле:
0x20000444 buffer2
0x20000b1c buffer1
Судя по сдвигу, размер buffer2 правильный
3. "Возможно есть некий буффер, мимо которого ваша программа "промахивается"" - по сути программа голая. я создал отдельный проект под эту ошибку и пытаюсь с ней разобраться. После запуска в main крутится while(1). После прихода любого пакета в UART возникает прерывание по тишине на линии.
код:

Код
void send_bytes_dma (uint8_t * data_ptr, uint16_t len)
//послать данные через DMA
{
DMA1_Channel2->CCR &= ~DMA_CCR_EN;                                 //выключаем канал DMA
DMA1_Channel2->CMAR = (uint32_t) data_ptr;                            //Записываем адрес данных
DMA1_Channel2->CNDTR = len;                                       //количество байт на передачу
DMA1_Channel2->CCR |= DMA_CCR_EN;                                 //включаем канал DMA
}

void sendCh(uint8_t ch)
//Послать символ
{
while(!(USORT1->ISR & USORT_ISR_TC ));                            //Ждем установки флага TC - завершения передачи
USORT1->TDR = ch;
}

void send_bytes (uint8_t * data, uint16_t len)
//послать команду длиной len байт на юарт
{
for(int i=0; i<len; i++) sendCh(data[i]);                            //передаем байт
while(!(USORT1->ISR & (1<<6) ));                                  //Ждем установки флага TC - завершения передачи
}

//обработчик прерывания тишины линии на USORT1
void USORT1_IRQHomdler(void)
{
USORT1->ICR |= USORT_ICR_RTOCF;                                    //очищаем флаг прерывания тишины на линии RTOF

for(int i = 0 ; i<1700; i++) buffer1[i] = 0xBB;
send_bytes(buffer1, 1700);                                       //выслать обратно обычным способом (пакет на выходе валидный)
delay_ms(50);
send_bytes_dma(buffer1, 1700);                                    //выслать обратно через DMA (пакет на выходе НЕ ВАЛИДНЫЙ)

}
В прерывании массив высылается 2 способами. В первом случае пакет на выходе валидный. Во втором уже попорченный. И попорченность зависит от наличия второго массива.

То есть проблема вряд ли с DMA, проблема именно с этими массивами. Как то они мешают друг другу. Или я хз.

Попробую настроить отладку в эклипсе и посмотреть значения в массиве до и после отправок. Попробую понять, в каком месте портится массив.

"если сегмент не зануляется в стартапе - забейте его оттуда какими-нибудь 0xAA и после воспроизведения ошибки проверьте незанятые согласно map-файлу участки - если Нечто там наследило - точку прерывания на изменение данных по этим адресам. Забивать маской нужно до инициализации сегмента данных. :)"

Вроде бы массивы находятся в BSS и эта область должня зануляться. Но я на всякий случай пишу в массив в цикле 0xBB и потом отправляю его.
Понимаю, что что то может мешать друг другу, но пока что совсем не силен в расследовании подобного через map файл.
Если не трудно, подскажите, может что почитать нужно для лучшего понимания?

Вот например кусок с 2 массивами:
Код
 COMMON         0x20000444      0xdae ./obj/interfosi.o
0x20000444                buffer2
0x20000b1c                buffer1
0x200011f4                . = ALIGN (0x4)
*fill*         0x200011f2        0x2
0x200011f4                _ebss = .
0x200011f4                __bss_end__ = _ebss
А вот кусок с одним массивом:
Код
COMMON         0x20000444      0x6d6 ./obj/interfosi.o
0x20000444                buffer1
0x20000b1c                . = ALIGN (0x4)
*fill*         0x20000b1a        0x2
0x20000b1c                _ebss = .
0x20000b1c                __bss_end__ = _ebss
4. " Попробую угадать :) USORT1->TDR 16 битный регистр" - если и так, то при отправке в него пихаются 8 битные значения и ждем пока они будут отправлены. А DMA сам с юартом работает - это скрыто от пользователя. Но DMA все шлет правильно по количеству байт и порядку (тоже проверял). И в середине возникают какие то другие значения. А иногда зависает камень - явно что то пишется не туда.
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
30.07.2017, 12:40 8
У тебя все данные скорей всего идут с ошибками или будет зависит от того как компиляция пройдет вставишь перед массивом глобальную переменную которая собьет выравнивание и все приехали. void send_bytes_dma (uint8_t * data_ptr, uint16_t len) (uint32_t) data_ptr uint8_t buffer1[buffers_len]; у масива нет выравнивания . Второе как настроенно DMA по размерностям и читай про то какие размерности требует USORT ?? попробуй записать не BB а все значения разные сразу увидишь свои ошибки по DMA . при USORT1->TDR = ch; происходит преобразование и там проблем нет .
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 385
30.07.2017, 14:08 9
2. Memory Browser, в Эклипсине он всяко должен быть.

А посылать по DMA второй пакет надо не после программной выдержки в 50 мс, а по получению прерывания от DMA по завершению передачи. Там посмотрите по документации, у DMA есть такое прерывание TCIF - transfer somplete interrupt flag зовется.

А, пардон, первый пакет высылается не через DMA?
и вообще, что-то там дико неправильно... Писали бы как положено.
У вас размеры DMA то какие выставлены? имею ввиду, что 8 бит / 8 бит?
Не помню, есть ли в 051 в DMA буфер FIFO... Он может упаковывать пакет по-своему, если не совпадают размеры. В документации описано.
0
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,406
30.07.2017, 14:27 10
Как это вообще может работать, когда в прерывании усарта выполняется отсылка длиннючего сообщения?
0
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 385
30.07.2017, 14:34 11
Во, точно! Надо же, я и предположить не мог. Хотя, по совести говоря, благодаря вноженным приоритетным прерываниям, такое можно и замутить. Но это будет скорее через жо.

Я ж говорю, писать надо по-человечьи, с чувством, с толком, с расстановкой. А не "как бык поссал" :) (поговорка).
0
0 / 0 / 0
Регистрация: 29.05.2015
Сообщений: 108
30.07.2017, 16:02 12
Код
void USORT1_IRQHomdler(void)
{
USORT1->ICR |= USORT_ICR_RTOCF;                                    //очищаем флаг прерывания тишины на линии RTOF

for(int i = 0 ; i<1700; i++) buffer1[i] = 0xBB;
send_bytes(buffer1, 1700);                                       //выслать обратно обычным способом (пакет на выходе валидный)
delay_ms(50);
send_bytes_dma(buffer1, 1700);                                    //выслать обратно через DMA (пакет на выходе НЕ ВАЛИДНЫЙ)
Очистку прерывания ставить надо по концу, если не охота думать
Нельзя молотить такое огромное количество времени в прерывании.
В настройках DMA есть биты, которые отвечают за направление/выравнивание/передачу одного элемента из массива, вполне возможно у Вас там ошибка.
0
Romziz
30.07.2017, 18:26 13
1. "Очистку прерывания ставить надо по концу, если не охота думать" - спасибо, наверное это правильно. я учту в будущем!
2. "Нельзя молотить такое огромное количество времени в прерывании." - это я понимаю. в оригинале контроллер молотит очень много данных - 4 мегабита по юарту через ESP8266 , на ПК принимает это все софт. Я специально разобрался в DMA, что бы разгрузить контроллер от обработки каждого принятого байта. Конкретно в этом случае контроллер больше ничем не занимается и пока он висит в прерывании - ничего больше не происходит. Поэтому не критично.

просто удобно по готовности анализировать интерфейс нажать в софтине кнопку, отправить пакет, и начать смотреть осциллограмму.
3. " В настройках DMA есть биты, которые отвечают за направление/выравнивание/передачу одного элемента из массива, вполне возможно у Вас там ошибка." в состоянии risit там нули и размерность указана байт \ байт (в массиве и в юарте), поэтому выравнивание и не нужно, вроде должно работать правильно. С направлением все ок, раз хоть что то отправляет.

4. "Я ж говорю, писать надо по-человечьи, с чувством, с толком, с расстановкой. А не "как бык поссал" :) (поговорка)." - можно конечно поставить в Main отправку этих массивов, но тогда я не успею отловить этот пакет анализатором после перепрошивки.

А так мне очень удобно. Посылаешь софтиной пакет нажатием кнопки, ловишь анализатором пакет на линии.

Или как иначе заставить выслать контроллер пакеты в нужный мне момент? и где должна быть эта отправка, если не в обработке прерывания внешнего события?

5. "Как это вообще может работать, когда в прерывании усарта выполняется отсылка длиннючего сообщения?" - очень просто, если есть понимание. пока на линии ничего нет, контроллер выполняет while(1).
Пришел пакет, линия снова пустая, вызывается ОДНОКРАТНОЕ прерывание по тишине на линии. Можно там хоть час сидеть - ничего другого контроллер не выполняет, других прерываний нет, если не слать второй пакет из ПК за эти 100 мс (но это мне делать незачем).

И это код для удобства тестирования конкретной возникшей проблемы. Все понимают, что нельзя в прерывании долго сидеть. Но это не запрещено)

6. "А, пардон, первый пакет высылается не через DMA?" - верно, первый пакет высылается через USORT1->TDR. Второй через DMA.
"и вообще, что-то там дико неправильно... Писали бы как положено." - этот код специально такой, что бы найти решение проблемы с массивами.

Я расскажу как было дело. Сначала был просто DMA, который отправляет пакет длиной 1700 байт.
Далее я заметил, что пакет какой то корявый.
Далее для проверки я так же решил выслать пакет обычным способом, не через DMA и увидел эту разницу.

"У вас размеры DMA то какие выставлены? имею ввиду, что 8 бит / 8 бит?" - да, по байту. Передача и прием работают правильно, проверял. Пока не начал использовать большой массив - никаких проблем небыло (и CRC пакетов всегда был валидный).

"буфер FIFO... Он может упаковывать пакет по-своему, если не совпадают размеры" - Представьте массив 1700 байт. первые 1500 полностью совпадают. Потом идет 20 байт рандомных. Остальные тоже полностью совпадают. Вряд ли весь пакет перепакован как то. Иначе дичь была бы во всем пакете, если я правильно понимаю.

Думаю не стоит заострять внимание на DMA , ибо он прекрасно работал. А проблемы 1 и 2 в первом сообщении явно связаны. То есть 2 больших массива мешают нормально работать и валят контроллер рандомными способами.

В первом случае просто при копировании элементов происходит зависание. Но стоит что то изменить (поменять имя массива) и все может работать нормально. Или удалить второй массив - тоже все адекватно при записи значений в первый.

7. "У тебя все данные скорей всего идут с ошибками или будет зависит от того как компиляция пройдет вставишь перед массивом глобальную переменную которая собьет выравнивание и все приехали." - можно пожалуйста по подробнее здесь ? У меня такое же ощущение. Что то меняешь в программе и может либо все виснуть, либо работать хорошо, а причины не понятны.

"У тебя все данные скорей всего идут с ошибками" - Пакет 1700 байт на 95% правильный и лишь в одном месте идут 20 байт каких то левых значений. Если бы что то было неправильно настроено, думаю ошибок было бы гораздо больше.
Хотя разными значения забивать массив я не пробовал. Попробую!
Не могли бы вы объяснить, что значит " у масива нет выравнивания" ? массив 8 битный. DMA настроен брать 8 бит из массива и класть 8 бит в UART. Вроде бы все настроено. По крайней мере при работе через DMA (отправка и прием) никаких проблем на буферах 100 - 200 байт не возникало. Всегда CRC совпадал (валидные пакеты).

PS. До дома пока не добрался что бы искать косяки через дебаг, вечером буду пробовать
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
30.07.2017, 19:02 14
Как раньше писал с данным процом не работал . Но как и думал ,USORT1->TDR 16 битный регистр, и работать с ним надо как с 16 битами, а не 8 битами .Transmit data rikystir (USORT_TDR) TDR[8:0]: Transmit data value. страница 707 .
0
Romziz
30.07.2017, 21:41 15
Transmit data rikystir (USORT_TDR)
Byts 31:9Riserved, must be kept at risit value.
Byts 8:0 TDR[8:0]: Transmit data value
Contains the data character to be transmitted.

Я что то неправильно понял? но вроде бы тут 8 рабочих бит, как бы сам регистр 32 битный, но только 8 используются. и значит не надо ему 16 бит запихивать.

И вы это вроде бы сами скопировали в предидущем сообщении.
0 / 0 / 0
Регистрация: 07.02.2106
Сообщений: 385
30.07.2017, 21:49 16
Надо в режиме отладки посмотреть, какие данные лежат действительно в массивах. остановить по брекпоинту после заполнения и посмотреть массив в памяти.
Так же, а какая скорость UART-а? она точно равна ли скорости на приеме, или есть процент ошибки? Ширина стоп-бита? Когда передается по-одиночке, ошибка скорости выравнивается, а когда идет непрерывным пакетом через DMA, ошибка скорости может накапливаться, и как раз через некоторое число байтов.
Я так пронимаю, что на приемной стороне стоит терминалка компа?
0
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
30.07.2017, 21:51 17
0...8-> 9 bit а не восемь
0
0 / 0 / 0
Регистрация: 29.05.2015
Сообщений: 108
30.07.2017, 21:58 18
Сделайте заранее, нужный Вам массив, а в прерывании просто вызовите DMA на отправку, и смотрите что выйдет.
Так же в начале объявления массива, объявите его c модификатором const, и просто передайте.
Если придет целым - значит проблема не в DMA/UART настройке.
Так же, можно помониторить например флаги DMA, который кстати - 3 штуки:
Half Transfer HTIF
Transfer Complete TCIF
Transfer Error TEIF
соответственно быть в курсе событий которые происходят при копировании.
0
Romziz
30.07.2017, 22:14 19
"0...8-> 9 bit а не восемь" - да , да .. есть еще 9 битный режим работы. но у меня 8 битный
"Но как и думал ,USORT1->TDR 16 битный регистр, и работать с ним надо как с 16 битами, а не 8 битами" - этого вашего высказывания я все равно не понял

"Надо в режиме отладки посмотреть, какие данные лежат действительно в массивах. остановить по брекпоинту после заполнения и посмотреть массив в памяти." пытаюсь, к сожалению слетели настройки и забыл как настроить дебаг.

"Так же, а какая скорость UART-а? она точно равна ли скорости на приеме, или есть процент ошибки?" - логический анализатор говорит, что скорость точная. 4 мегабита. у него есть режим автободрейт. если было бы нечто иное, он бы показал другие значения.

"Ширина стоп-бита? " - вот этого не знаю, а как узнать? есть такие параметры? важно ли это ?

"Я так пронимаю, что на приемной стороне стоит терминалка компа?" - я написал софтину, которая через сокеты общается с ESP8266, а она является uart-мостом на STM32.

Делаю принтер лазером по фоторезисту. Нужно передавать монохромную строку, что бы лазер пиксели рисовал. Скорость каретки большая, нужно иметь в запасе всегда текущую строку (для быстрого доступа) и следующую (что бы сразу начать печатать ее) и еще буфер, что бы принять новую строку от пк.

Соответственно 3 массива по 1700 байт примерно. около 5 кб озу. Всего 8 в камне

Еще хотел бы попробовать подключить к STM32 камеру 150 на 150 в монохроме. при 4 мегабитах должно быть что то около 15 кадров. Соответственно уменьшать битрейт очень не хотелось бы.

Но вот с такой, казалось бы, простой задачей возникли внезапные проблемы.

Заполнил массив в Main после старта камня:

Код
int main(void)
{
hardware_init();                                              //инициализируем порты
uart_init();                                                 //инициализация юарта
dma_init();                                                   //инициализируем работу DMA отправку данных
fill_buffer();                                                //заполняем буфер

while(1)                                                    //Главный цикл
{
LedChange();
delay_ms(1000);
}
}
Теперь при отправке буфера он сразу кривой. Даже через USORT->TDR

Вот так выглядит посылка - вокруг одинаковые байты, но внезапно начинается каша. Кто то туда гадит.

<Изображение удалено>

Далее я выключил заполнение массива - должны быть все нули, но нет:

<Изображение удалено>

Далее поставил Somst, ругнулось на функцию заполнения массива - закомментировал. Казалось бы ну уж точно должно быть то, что нужно, но нет:

<Изображение удалено>

Вот такая вот беда.

А если удалить второй массив, то все становится хорошо.
0 / 0 / 0
Регистрация: 29.05.2015
Сообщений: 108
30.07.2017, 22:47 20
Далее поставил Somst, ругнулось на функцию заполнения массива
Вы издеваетесь?
Код
uint8_t const  arr[LEN] = {0}; //ваш маccив с нулями
....
....
send_uart_dma(&arr, LEN) //ваш вызов DMA и передача буфера
Внимательно только смотрите какой аргумент ожидает функция отправки (адрес/указатель)
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.07.2017, 22:47
Помогаю со студенческими работами здесь

Ошибки с большими массивами
Нужно заполнить массив ссылками на пиксели. Если между try и except отнять 2 вместо 1 массив...

Работа с большими массивами данных
Здравствуйте! Я работаю над курсовым проектом, в нём используется папка с данными. Они хранятся в...

Операции с большими массивами данных
Доброе время суток! Мне нужно оперировать большими объемами данных - массивы до 4 Гб....

Как правильно работать с большими массивами?
Здоровый у меня массив. 30000 строк. И постоянно обновляется. Я его постоянно очищаю If...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru