Библиотеки и вы

Проголосовало: 114 | Воздержалось: 13

Любопытства пост. Знаю что это тема постоянных холиваров, но просто интересно поглядеть статистику о том, кто какой стиль работы предпочитает. Речь идет о библиотеках для облегчения работы с периферией внутри мк, которые как правило любезно предоставляются производителем.
  • 0
  • 24 февраля 2015, 00:00
  • 1essor1

Комментарии (53)

RSS свернуть / развернуть
Эну например я искал пример для епрома на stm32f3 — он отличается несколько периферией от f1 и в кокосе был очень странный пример — видимо с новомодной stm либой (как она там cpal?), но там по сути spl в обертке (мне не особо нужной), я забрал, что хотел как пример для spl и вроде работает :) и не хочу я всю эту портянку.
0
и не хочу я всю эту портянку
Сами либы — это еще не портянка. Настоящая МЕГАПОРТЯНКА располагается обычно в \Device\MCU_subfamily\Include\MCU_chip_xxx.h.

Вот это портянка — так портянка: до 30-40 тыс. строк. Ее еще называют изучающие арм — CMSIS файл_описания_периферии (он генерируется производителем из соответствующего xml-файла SVD), хотя он должен присутствовать в либе и даже при отсутствии самого CMSIS. Стандартное, от самого производителя — избавление от магических чисел, весом до полмега.

Ее конечно же можно переписать самому для себя лично(очень частично есно), в целях самопрограммирования мозга на этапе изучения чипа, т.е. вбивания инфы из даташита. Только зачем? Но юзая либы, т.е. ползая по конкретным и в сотни/тысячи раз меньшим файлам .c и .h либы(например, ADC или GPIO) как-то проще увидеть то, что именно и надо(в том числе и уже определенное в той мегапортянке), и как это выглядит, чем ползать по самому этому мегахидеру.
+1
Т.е. пишут обычно свои ПРОКЛАДКИ поверх этой МЕГАПОРТЯНКИ(определение своих имен персональных и специфичных для своей задачи посредством переопределения имен из мегахидера), но Init'ы периферии обычно берут из либы. Манипулировать битами можно и без либы — напрямую или через свои макросы, но все равно с учетом именований из того мегахидера, хотя возможно уже через свою хидер-прокладку.
0
Сам вопрос построен неверно. Какого уровня библиотеки? Если уровня «полноценная реализация FAT», или «декодирование JPEG» — буду искать чужие. Если задача «мигание светодиодом» — то зачем там вообще библиотеки?
+1
  • avatar
  • e_mc2
  • 24 февраля 2015, 01:07
Там вообщем-то вопроса то и нет в прямом виде) Но замечание учел, текст поправил.
0
Двачую. Писать свой велосипед для TCP/IP, или Fatfs это занятие глупое и неблагодарное. А переписать говнолибу от криворуких индусов дело кошерное и багоугодное.
+5
А переписать говнолибу от криворуких индусов дело кошерное и БАГОугодное.
Это юмор такой, или просто «текст пропитанный ненавистью» к доморощенным оглашенным «энтузиастам»?
0
Моего варианта нет: все и сразу. В зависимости от проекта. Могу и на асме наваять, могу использовать SPL.
+2
Ну вообщем-то можно подвести итог о том, что программисты из того же ST не зря хлеб едят — как бы не хаяли библиотеки, но большинство на них и сидит.
0
SPL хорошо использовать, например, чтобы инициализировать периферию (таймеры, GPIO, DMA). Далее в программе идёт только работа с регистрами.
0
я в одном из проектов ваще делал следующим образом:
#define BAUDRATE			250000
#define INTERFACE_BRR(CLK, BDR)					(((CLK)+((BDR)>>1))/(BDR))
#define TIM_FREQ1(CLK, FREQ)							(((CLK)/(FREQ)/2)-1)
#define TIM_FREQ2(CLK, FREQ)							(((CLK)/(FREQ))-1)

#define TIM1_PSC(CLK)										((CLK)/10000-1) 					// 0.1 ms
#define TIM1_ARR												((MEASURE_MS) * 40 - 1) 	// 400 ms
#define TIM1_HALF												((MEASURE_MS) * 20 - 1)		// 200 ms
// RCC setup constants
const RCC_TypeDef RCC_ = {0x03035483, 0x001D840A, 0, 0, 0, 0x00000017, 0x0000EE7D, 0x001E483F, 0, 0};
const RCC_TypeDef RCC_MASK = {0x030F00FB, 0x077FFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0};

//AFIO setup constants
const AFIO_TypeDef AFIO_ = {0,0x0200003C, 0x00000000, 0x00000001, 0x00000000, 0x00000000};
const AFIO_TypeDef AFIO_MASK = {0,0xF8FFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};

// GPIO setup constants

const GPIO_TypeDef GPIO_A = {0x81000003, 0x344688BB, 0, 0x00002900, 0, 0, 0};
const GPIO_TypeDef GPIO_B = {0x8B383438, 0xB8B388B6, 0, 0x00000C91, 0, 0, 0};
const GPIO_TypeDef GPIO_C = {0x88880000, 0x333B6688, 0, 0x000003D0, 0, 0, 0};
const GPIO_TypeDef GPIO_D = {0x38B38863, 0x3888838B, 0, 0x00005654, 0, 0, 0};
const GPIO_TypeDef GPIO_E = {0x83333333, 0x83883888, 0, 0x00002501, 0, 0, 0};

const GPIO_TypeDef GPIO_A_MASK = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFF7CBE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
const GPIO_TypeDef GPIO_B_MASK = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFFEDD5,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
const GPIO_TypeDef GPIO_C_MASK = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFF1FFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
const GPIO_TypeDef GPIO_D_MASK = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFF7B6E,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
const GPIO_TypeDef GPIO_E_MASK = {0xFFFFFFFF,0xFFFFFFFF,0x00000000,0xFFFFB780,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};

// SPI3 setup constants
const SPI_TypeDef SPI_2 = {0x0364, 0, 0x0040, 0};
const SPI_TypeDef SPI_2_MASK = {0xFFFF, 0,  0xFFFF, 0};

// ADC setup constants

const ADC_TypeDef ADC_1 = { 0, 0x00010180, 0x0000F001, 0,0,0,0,0,0,0x00000FFF,0,0,0,0,0x00229060};
const ADC_TypeDef ADC_2 = { 0, 0x00000100, 0x0000F001, 0,0,0,0,0,0,0x00000FFF,0,0,0,0,0x002105A0};
const ADC_TypeDef ADC_3 = { 0, 0x00000100, 0x0000F001, 0,0,0,0,0,0,0x00000FFF,0,0,0,0,0x00262D40};

const ADC_TypeDef ADC_MASK = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                                  0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
// DMA setup constants
typedef struct
{
  __IO uint32_t CCR;
  __IO void* CNDTR;
  __IO void* CPAR;
  __IO void* CMAR;
} DMA_Channel_TypeDef_;

const DMA_Channel_TypeDef_ DMA1_2 = {0x00000090, 0,&(USART3->DR),TX2_3.Buffer};
const DMA_Channel_TypeDef_ DMA1_4 = {0x00000090, 0,&(USART1->DR),TX1.Buffer};
const DMA_Channel_TypeDef_ DMA1_7 = {0x00000090, 0,&(USART2->DR),TX2_3.Buffer};
//const DMA_Channel_TypeDef_ DMA2_5 = {0x00001090, 0,&(UART4->DR),TX4.Buffer};

const DMA_Channel_TypeDef DMA_MASK = {0xFFFFFFFF, 0,0xFFFFFFFF,0xFFFFFFFF};

// USART setup constants

const USART_TypeDef USART_1 = {0,0,0,0,INTERFACE_BRR(RTE_PCLK2, BAUDRATE),0,0x206C,0,0,0,0x0080,0,0,0};
const USART_TypeDef USART_2 = {0,0,0,0,INTERFACE_BRR(RTE_PCLK1, BAUDRATE),0,0x206C,0,0,0,0x0080,0,0,0};
const USART_TypeDef USART_3 = {0,0,0,0,INTERFACE_BRR(RTE_PCLK1, BAUDRATE),0,0x206C,0,0,0,0x0080,0,0,0};
const USART_TypeDef UART_5 = {0,0,0,0,INTERFACE_BRR(RTE_PCLK1, BAUDRATE),0,0x202C,0,0,0,0,0,0,0};

const USART_TypeDef USART_MASK = {0,0,0,0,0xFFFF,0,0xFFFF,0,0xFFFF,0,0xFFFF,0,0xFFFF,0};

// Timers setup constants
//Fast timers
const TIM_TypeDef TIM_4 = {0x0000, 0, 0, 0, 0, 0, 0x0011, 0, 0, 0, 0, 0, 0, 0, 0x6400, 0, 0x1000, 0, 0, 0, 0, 0, TIM_FREQ2(RTE_PCLK2,SWx_n_FREQ), 0,0,0,
                           0,0,0,0,0,0,TIM_FREQ1(RTE_PCLK2,SWx_n_FREQ),0};
const TIM_TypeDef TIM_4_MASK = {0xFFFE, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0,0,0,
                                0,0,0,0,0,0,0xFFFF,0};

//Reserve Timers
const TIM_TypeDef TIM_1 = {0x0001, 0, 0, 0, 0, 0, 0x0008, 0, 0, 0, 0, 0, 0x6464, 0, 0, 0, 0x0031, 0, 0, 0, TIM1_PSC(RTE_PCLK2), 0, TIM1_ARR, 0, 0, 0,
													 TIM1_HALF, 0, TIM1_HALF, 0, (MEASURE_MS*10)*0.5, 0, 0, 0, 0x8000, 0, 0, 0, 0x0001, 0};
const TIM_TypeDef TIM_1_MASK = {0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0,0,0,
                                0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0xFFFF, 0, 0, 0, 0xFFFF, 0};

const TIM_TypeDef TIM_5 = {0x0000, 0, 0, 0, 0, 0, 0x0011, 0, 0, 0, 0, 0, 0, 0, 0x6400, 0, 0x1000, 0, 0, 0, 0, 0, TIM_FREQ2(RTE_PCLK2,SWx_n_FREQ), 0,0,0,
                           0,0,0,0,0,0,TIM_FREQ1(RTE_PCLK2,SWx_n_FREQ),0};
const TIM_TypeDef TIM_5_MASK = {0xFFFE, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0, 0xFFFF, 0,0,0,
                                0,0,0,0,0,0,0xFFFF,0};

//Interrupt setup constants

/*  __IO uint32_t IMR;
  __IO uint32_t EMR;
  __IO uint32_t RTSR;
  __IO uint32_t FTSR;
  __IO uint32_t SWIER;
  __IO uint32_t PR;
*/																
																
const EXTI_TypeDef EXT_I = {0x00000010, 0x00000000, 0x00000010, 0x00000010, 0x00000000, 0x00000000};
const EXTI_TypeDef EXTI_MASK = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000};


void Init_Periph(void* Periph, void* Struct, void* MaskStruct, uint32_t Length)
{
	uint32_t i;
	static uint32_t mask;
	for (i=0;i<Length;i+=4)
	{
		mask =(*(uint32_t*)((uint32_t)MaskStruct+i));
		if (mask)
			(*(uint32_t*)((uint32_t)Periph+i)) = (*(uint32_t*)((uint32_t)Struct+i));
	}
}

void Init_Periphs(void)
{
	Init_Periph(RCC,(void*)&RCC_,(void*)&RCC_MASK,sizeof(RCC_));
	Init_Periph(AFIO,(void*)&AFIO_,(void*)&AFIO_MASK,sizeof(AFIO_));

	Init_Periph(TIM4,(void*)&TIM_4,(void*)&TIM_4_MASK,sizeof(TIM_4));
	Init_Periph(TIM5,(void*)&TIM_5,(void*)&TIM_5_MASK,sizeof(TIM_5));
	Init_Periph(TIM1,(void*)&TIM_1,(void*)&TIM_1_MASK,sizeof(TIM_1));

	Init_Periph(SPI2,(void*)&SPI_2,(void*)&SPI_2_MASK,sizeof(SPI_2));

	Init_Periph(ADC1,(void*)&ADC_1,(void*)&ADC_MASK,sizeof(ADC_1));
	BIT_BAND_PER(ADC1->CR2,ADC_CR2_CAL) = 1;
	Init_Periph(ADC2,(void*)&ADC_2,(void*)&ADC_MASK,sizeof(ADC_2));
	BIT_BAND_PER(ADC2->CR2,ADC_CR2_CAL) = 1;
	Init_Periph(ADC3,(void*)&ADC_3,(void*)&ADC_MASK,sizeof(ADC_3));
	BIT_BAND_PER(ADC3->CR2,ADC_CR2_CAL) = 1;

	Init_Periph(USART1,(void*)&USART_1,(void*)&USART_MASK,sizeof(USART_1));
	Init_Periph(USART2,(void*)&USART_2,(void*)&USART_MASK,sizeof(USART_2));
	Init_Periph(USART3,(void*)&USART_3,(void*)&USART_MASK,sizeof(USART_3));
	Init_Periph(UART5,(void*)&UART_5,(void*)&USART_MASK,sizeof(UART_5));

	Init_Periph(GPIOA,(void*)&GPIO_A,(void*)&GPIO_A_MASK,sizeof(GPIO_A));
	Init_Periph(GPIOB,(void*)&GPIO_B,(void*)&GPIO_B_MASK,sizeof(GPIO_B));
	Init_Periph(GPIOC,(void*)&GPIO_C,(void*)&GPIO_C_MASK,sizeof(GPIO_C));
	Init_Periph(GPIOD,(void*)&GPIO_D,(void*)&GPIO_D_MASK,sizeof(GPIO_D));
	Init_Periph(GPIOE,(void*)&GPIO_E,(void*)&GPIO_E_MASK,sizeof(GPIO_E));

	Init_Periph(EXTI,(void*)&EXT_I,(void*)&EXTI_MASK,sizeof(EXT_I));


	Init_Periph(DMA1_Channel2,(void*)&DMA1_2,(void*)&DMA_MASK,sizeof(DMA1_2));
	Init_Periph(DMA1_Channel4,(void*)&DMA1_4,(void*)&DMA_MASK,sizeof(DMA1_4));
	Init_Periph(DMA1_Channel7,(void*)&DMA1_7,(void*)&DMA_MASK,sizeof(DMA1_7));
//	Init_Periph(DMA2_Channel5,(void*)&DMA2_5,(void*)&DMA_MASK,sizeof(DMA2_5));

	
}

int Verify_Periph(void* ComparePeriph, void* CompareStruct, void* MaskStruct, uint32_t Length)
{
	uint32_t i;
	uint32_t mask;
	for (i=0;i<Length;i+=4)
	{
		mask =(*(uint32_t*)((uint32_t)MaskStruct+i));
		if (mask)
			if ( ((*(uint32_t*)((uint32_t)ComparePeriph+i)) & mask) !=
					 ((*(uint32_t*)((uint32_t)CompareStruct+i)) & mask))
			return 0;
	}
	return 1;
}

int Verify_Periph_All(void)
{
	if (Verify_Periph(GPIOA,(void*)&GPIO_A,(void*)&GPIO_A_MASK,sizeof(GPIO_A)))
	if (Verify_Periph(GPIOB,(void*)&GPIO_B,(void*)&GPIO_B_MASK,sizeof(GPIO_B)))
	if (Verify_Periph(GPIOC,(void*)&GPIO_C,(void*)&GPIO_C_MASK,sizeof(GPIO_C)))
	if (Verify_Periph(GPIOD,(void*)&GPIO_D,(void*)&GPIO_D_MASK,sizeof(GPIO_D)))
	if (Verify_Periph(GPIOE,(void*)&GPIO_E,(void*)&GPIO_E_MASK,sizeof(GPIO_E)))
		return 1;
	return 0;
}


Жестоко.

Но: Приложение АРХИ-ответственное. И приходилось проверять все настройки периферии. А это, знаете-ли, то еще занятие!
Поэтом и был выбран именно такой вариант
0
Не совсем понял, ты проводишь проверку констант для инициализации? Почему бы тогда не использовать ассерты и нагрузить препроцессор вместо мк?
0
в основном цикле идет проверка действующей периферии по маске. Те биты, которые в процессе работы должны изменяться — отбрасываются по маске. Проверяются константные величины.
Функция Verify_Periph_All() вызывается в основном цикле. Если получаем единичку- то все хорошо, если ноль — сбрасываемся
0
Те биты, которые в процессе работы должны изменяться — отбрасываются по маске. Проверяются константные величины.
Функция Verify_Periph_All() вызывается в основном цикле. Если получаем единичку- то все хорошо, если ноль — сбрасываемся
А чем обусловлен такой подход к проверке регистров периферии? Боитесь, что код (в результате сбоя) перезапишет область регистров?
0
ну так периыерия работает, движется, какие-то биты в процессе работы изменяются (в прерываниях например). Есть регистры которые не желательно просто так читать. Например регистр данных DR в USART. Поэтому напротив него маска 0. Дескать, даже и не пытайся. А вот стационарные данные считывать оттудова — вполне возможно.
0
код, перезапишет, космические лучи, помеха по питанию, на мало ли чего? ОЗУ — и есть ОЗУ. Имеет право напортачиться.
0
космические лучи
Вероятность этого события почти 0, если аппаратура не в космосе.
помеха по питанию
Если разведено нормально, то помех не будет.
+1
Понял. Дело конечно ваше, но я не вижу большого смысла в такой проверке (и не видел применения подобного подхода).
«космические лучи» могут задеть те регистры, которые моментально выдует программу из строя, эти лучи также могут перезаписать таблицу векторов прерывания, стек, что тоже моментально убьет программу…
+1
все правильно, только про вероятность не согласен. Вероятность почти нулевая, если компьютер находится в подземелье на глубине более 50м. В инете можно почитать про эксперименты. Лень искать. Не об этом тема… В случае вылета программы есть и сторожевые таймеры и специальные алгоритмы проверки правильности работы программы. Цель всего этого — не в том, чтобы не допустить слетания програмы, а в том, чтобы эта программа или устройство чего-то там не напортачила ненужного. Например, имеется стрелка на ж.д. путях. Смысл в том, чтобы случайно не перевести ту самую стрелку, куда не следует.
0
Про нулевую вероятность писал не я, я даже соглашусь с Вами, что такая вероятность хоть и очень-очень мала, но существует.

Но я считаю (сугубо ИМХО, повторюсь, вы разработчик, вам решать) что ваша идея проверки периферии не эффективна.

Есть некие практики для разработки надежных и отказоустойчивых систем. Если мы говорим о надежности ПО – то они начинаются с самой методологии (как пример, уже упомянутый MISRA), далее идет разного ровная тестирование (модульное, функциональное, нагрузочное и т. д.) и вплоть до формальной верификации кода…

Если говорим о внешних факторах (лучи, питание, выход из строя МК) есть другие решения, например многократное резервирование (с арбитром или несколькими арбитрам). Эти меры достаточно эффективно закрывают очень широкий спектр потенциальных отказов.

А ваш метод вроде и что-то проверяет, но в очень узком диапазоне отказов. И эта проверка содержит код, который в свою очередь тоже потенциально может стать источником ошибки.

З.Ы.

А вот у меня на фронте случай был… Икал ошибку в финансовой (банковской) программе. Нашел. Там был простой подсчет типа СУММА =ЦЕНА * КОЛЛИЧЕСТВО. И мой юный коллега решил после подсчета сделать «проверку умножения» и дописал ниже КОЛЛИЧЕСТВО = СУММА / ЦЕНА. Если КОЛЛИЧЕСТВО сошлось – то все ОК. На вопрос «а зачем он это сделал» он ответил «на всякий случай, а вдруг что-то сбойнет, ведь лишняя проверка не помешает». Проблема в том, что при ЦЕНА = 0 (а это был допустимый юзкейс) сервер валился с эксепшином деления на 0…
+1
резервирование и двухпроцессорное управление тоже присутствует. поприкидываю над эффективностью работы периферии
0
проверяется именно область периферии на соответствие константам во флеши. Память программ отдельно проверяется по контрольным суммам.
0
mask =(*(uint32_t*)((uint32_t)MaskStruct+i));

Сурово так…

Еcли я правильно декодировал логику, то можно переписать все намного проще.
Делам одно приведение перед циклом
uint32_t * MaskArray = (uint32_t*) MaskStruct;

и потом просто используем массив (пусть адресной арифметикой занимается компилятор)
mask = MaskArray[i];

аналогично с ComparePeriph

только нужно соответственно скорректировать цикл, что-то типа
for (i = 0; i < Length / sizeof(uint32_t); i++)
0
Вообще, наборы правил вроде MISRA, ЕМНИП, не советуют подобные фокусы (это и к оригинальному коду относится).
0
Да, более того, на некоторых платформах этот код потенциально может упасть из-за чтения невыровненных данных. Мое замечание сугубо по оформлению кода, а не по логике работы.
0
по поводу некоторых других платформах — здесь вообще не вариант. Данная писака жестко привязана к определенному камню.
0
а что именно ЕМНИП запрещает в данном случае?
0
Rule 45 (required): преобразований типов из/в указатель не разрешены. Это правило также применимо к преобразованию указателя на один тип данных в указатель на другой тип данных.
0
интересно, а как будет вызываться функция копирования памяти? там как раз игнорируются всякие типы данных. Получается, что memcpy — против правил.
В данном случае, скорее это как рекомендация. Потому что даже в дельфях преобразование типов возможно и в ряде случаев необходимо.
0
Для MISRA C это обязательное правило. Но, еcли вы не планируете проходить сертификацию – можете рассматривать его как рекомендацию.
0
еcли вы не планируете проходить сертификацию
Misra обязательна для сертификации? Это для каких применений?
И как при этом Misra и С++ уживаются?
0
Нет, официальной сертификации нет. Я некорректно употребил термин.
Но многие разработчики сами вводят контроль кода по правилам MISRA (внутреннюю процедуру «сертификации» ).
0
разработчики сами вводят контроль кода
Понятно — сами себя ограничивают…
0
Не всегда сами себя. Это может быть требованием заказчика.
0
И как при этом Misra и С++ уживаются?
А никак. C only.
0
Вроде уже существует MISRA C++?
0
Правда? Нинай, не видел. Надо будет посмотреть.
0
А никак. C only.
Зачем же такое самоограничение? Самому себе руки связывать — странно это…
0
MISRA — изначально набор правил по программированию автомобильных систем управления, предназначенный для повышения надежности ПО. Но он пришелся по нраву и другим областям эмбеда, где требуется повышенная надежность. Правила MISRA запрещают использование тех средств языка, которые часто приводят к ошибкам и непортируемому коду.
В общем, для тог, чтобы писать более надежные программы.
0
www.misra.org.uk/shop/buy_now.php
MISRA C++:2008 — Guidelines for the use of the C++ language in critical systems. PDF = £15.00
0
О, любопытно. Где бы его еще достать назаляву.
0
сертификация как раз планируется. И все же, как копировать область памяти, выделенную под различные типы данных без приведения? Тупо а = а1; b = b1? Это разве разумно? В моем случае, копирование и сравнение с учетом маски. Другой разумный вариант можете предложить?
0
сертификация как раз планируется
Какая именно? От Вас требуют MISRA C?
Тупо а = а1; b = b1? Это разве разумно?

Ну, да, через «равно», если я Вас правильно понял. Это хоть и тупо, зато типобезопастно (в отличии от манипуляций с указателями и прямой работой с памятью без контроля типов). MISRA он суров и это только одно из ограничений, которое он накладывает.
0
Откуда скопировал? Поделись. Я хотел утащить официальный гайд мисры, но он оказался закрытым. Пока что руководствуюсь документиком из комплекта IAR'а, но он не без недостатков.
0
Да, они платные.
Брал отсюда. Но это выжимка и в актуальности я не уверен.
0
Там в конце прикреплена ссылка на документ. Похоже, что это оригинальный MISRA C 1998.
Но неплохо бы еще раздобыть C:2004, C:2012 и C++:2008.
+1
Да, я не заметил.
Похоже на оригинал.
0
+3
Решил поискать какие правила существуют, нашел стандарты программирования НАСА, правда тоже кастрированные.
0
ЕМНИП, этот стандарт начинается с указания «сперва выполните все требования мисры».
0
Сомнительные приведения типов и закладывание на их внутреннее представление (даже с интом могут быть разночтения — есть минимум три варианта кодирования отрицательных чисел — прямой, обратный, дополнительный). Но конкретный номер правила не приведу.
0
по вашим замечаниям переделал
void Init_Periph(void* Periph, uint32_t* Struct, uint32_t* MaskStruct, uint32_t Length)
{
	uint32_t i;
	for (i = 0; i < Length/sizeof(uint32_t); i++)
	{
		if (MaskStruct[i])
			((__IO uint32_t*)Periph)[i] = Struct[i];
	}

int Verify_Periph(void* ComparePeriph, uint32_t* CompareStruct, uint32_t* MaskStruct, uint32_t Length)
{
	uint32_t i;
	uint32_t mask;
	for (i = 0; i < Length/sizeof(uint32_t); i++)
	{
		mask = MaskStruct[i];
		if (mask)
			if ( (((__IO uint32_t*)ComparePeriph)[i] & mask) != (CompareStruct[i] & mask) )
				return 0;
	}
	return 1;
}

int Verify_Periph_All(void)
{
	if (Verify_Periph(GPIOA,(uint32_t*)&GPIO_A,(uint32_t*)&GPIO_A_MASK,sizeof(GPIO_A)))
	if (Verify_Periph(GPIOB,(uint32_t*)&GPIO_B,(uint32_t*)&GPIO_B_MASK,sizeof(GPIO_B)))
	if (Verify_Periph(GPIOC,(uint32_t*)&GPIO_C,(uint32_t*)&GPIO_C_MASK,sizeof(GPIO_C)))
	if (Verify_Periph(GPIOD,(uint32_t*)&GPIO_D,(uint32_t*)&GPIO_D_MASK,sizeof(GPIO_D)))
	if (Verify_Periph(GPIOE,(uint32_t*)&GPIO_E,(uint32_t*)&GPIO_E_MASK,sizeof(GPIO_E)))
		return 1;
	return 0;
}

надеюсь, будет работать)))
0
надеюсь, будет работать)))
Ну, лучше все же протестировать :)
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.