Миландр

Ключевым подразделением нашей компании
является Центр Проектирования интегральных микросхем
Текущее время: 2020-окт-29 02:53

Часовой пояс: UTC+03:00




Начать новую тему  Ответить на тему  [ 3 сообщения ] 
Автор Сообщение
СообщениеДобавлено: 2016-ноя-12 16:47 
Не в сети

Зарегистрирован: 2010-фев-18 20:41
Сообщения: 7
Откуда: Voronezh
Доброго всем дня!
Хотелось бы услышать экспертное мнение по следующему вопросу.
Не знаю насколько важны детали, поэтому для первого случая кратко изложу суть. Скажу лишь что весь проект основан на примере, взятом с этого сайта для работы с Ethernet.
Сразу оговорюсь, что проблему удалось обойти, о чем будет изложено ниже, но непонимание осталось.
Итак... Определяется некий тип, представляющий собой данные, упакованные в структуру. Существует функция, аргументом которой выступает указатель на наш тип данных.
Далее мы объявляем статический объект нашего типа (глобальный) и используем его адрес при вызове функции в качестве аргумента.
В функции происходит обращение к ячейке памяти по адресу, который мы ей передали (см. скриншот 1). При этом возникает исключительная ситуация (см. скриншот 2).
Идем далее, точнее возвращаемся на исходную ...
Вместо объявления статического объекта нашего типа, мы объявляем статический массив необходимой длинны, а затем объявляем указатель на наш тип данных и присваиваем ему адрес созданного массива. Далее этот указатель используем при вызове функции так же как в первом случае (передаем в качестве аргумента).
В функции точно также происходит обращение к ячейке памяти по адресу, который мы ей передали (см. скриншот 3). При этом исключительная ситуация не возникает (см. скриншот 4), и мы видим что счетчик цикла увеличился на единицу.
Вопрос в том, почему так происходит...?

Привожу фрагменты текста исходного кода:
//----------------------------------------------
// Определение нашего типа
typedef struct 
{
 ETH_HDR ethernet_protocol;
 IP_HDR	 internet_protocol;
 UDP_HDR user_datagram_protocol;
 MY_HDR  my_protocol;
 uint8_t data[1000];
 uint16_t data_size;
 uint16_t hdr_size;
} MY_FRAME;
//----------------------------------------

//----------------------------------------
// Объявление объекта
// вариант 1 (нерабочий):
/*
MY_FRAME output_;
MY_FRAME* output = &output_;
*/
// вариант 2 (рабочий):
uint16_t buffer[750];
MY_FRAME* output = (MY_FRAME*)buffer;
//--------------------------------------------------------

// как происходит вызов функции
output->hdr_size = sizeof(ETH_HDR) + sizeof(IP_HDR) + sizeof(UDP_HDR) + sizeof(MY_HDR);  // определяем одно из полей структуры
MySendPacket(output);   // вызываем функцию


// Тело функии (практически из примера, с небольшими изменениями под свою структуру данных)
MySendPacket(MY_FRAME* frame) 
{
    uint16_t i;
    uint32_t tmp,head,tail;
    uint32_t *src,*dst;
    uint16_t space[2];
	
    uint32_t* buffer = (uint32_t*)frame;
    uint32_t size = frame->hdr_size + frame->data_size + 4;
	
    head = ETHERNET->X_Head;
    tail = ETHERNET->X_Tail;
    
    if(head>tail) {
       space[0]=head-tail;
       space[1]=0;
    }
    else {
       space[0]=0x2000-tail;
       space[1]=head-0x1000;
    }
    
    if(size>(space[0]+space[1]-8)) return;	

    tmp=size;
    src=buffer;
		 
    dst=(uint32_t*)(0x38000000+tail);
	
    *dst++ =tmp;
    space[0]-=4;
    if((uint16_t)dst>0x1FFC) dst=(uint32_t*)0x38001000;

    tmp=(size+3)/4;

    if(size<=space[0]) {
	for(i=0; i<tmp; i++) {
	   *dst++ = *src++;       // уходит в HardFault_Handler при первом варианте
	} 	
    }
    else {
        tmp-=space[0]/4;
        for(i=0;i<(space[0]/4);i++) {
	   *dst++ = *src++;
	}
	dst=(uint32_t*)0x38001000;
	for(i=0;i<tmp;i++) {
	   *dst++ = *src++;
	}
    }
    
    if((uint16_t)dst>0x1FFC)	dst=(uint32_t*)0x38001000;
    tmp=0;
    *dst++ =tmp;
    if((uint16_t)dst>0x1FFC)	dst=(uint32_t*)0x38001000;

    ETHERNET->X_Tail=(uint16_t)dst;

}



Вложения:
Комментарий к файлу: Скриншот 1 - собираемся прочитать данные из ячейки памяти (вариант 1)
[ attachment ]
screen1.jpg [ 452.36 КБ | 2236 просмотров ]
Комментарий к файлу: Скриншот 2 - Возникновение исключительной ситуации через шаг после скриншота 1.
[ attachment ]
screen2.jpg [ 463.81 КБ | 2236 просмотров ]
Комментарий к файлу: Скриншот 3 - Собираемся прочитать данные из ячейки памяти (вариант 2)
[ attachment ]
screen3.jpg [ 465.39 КБ | 2236 просмотров ]
Комментарий к файлу: Скриншот 4 - Следующий шаг после скриншота 3: успешное чтение из памяти и переход к следующей итерации цикла
[ attachment ]
screen4.jpg [ 448.79 КБ | 2236 просмотров ]
Вернуться к началу
СообщениеДобавлено: 2016-ноя-12 18:47 
Не в сети

Зарегистрирован: 2010-сен-21 12:57
Сообщения: 748
Откуда: г. Санкт-Петербург
В первом случае происходит чтение целого по адресу не кратному 4 (R2 = 0x20000bea), поэтому Hard Fault.
При объявлении структуры ее адрес д.б. выровнен по 4.
Во втором случае объявленный массив видимо случайно был выровнен по 4, поэтому Hard Fault не происходит.


Вернуться к началу
СообщениеДобавлено: 2016-ноя-13 17:26 
Не в сети

Зарегистрирован: 2010-фев-18 20:41
Сообщения: 7
Откуда: Voronezh
Благодарю за консультацию!
Действительно, в спецификации на микроконтроллер сказано:
Цитата:
Процессор поддерживает доступ по невыровненным адресам только для следующих
инструкций:
LDR;
LDRH;
LDRSH;
STR;
STRH.
Все остальные инструкции при попытке доступа по невыровненному адресу
генерируют исключение (Hardfault). Более подробно данный вопрос рассмотрен в разделе
«Обработка отказов».
Как говориться надо учить матчасть...
Еще раз спасибо!


Вернуться к началу
Показать сообщения за:  Поле сортировки  
Начать новую тему  Ответить на тему  [ 3 сообщения ] 

Часовой пояс: UTC+03:00


Кто сейчас на конференции

Сейчас этот форум просматривают: Bing [Bot] и 9 гостей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Перейти: 

cron
Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB