eddy_em: (Костерок)
[personal profile] eddy_em
Т.к. для подключения более приличного экранчика с параллельной шиной данных мне понадобится сравнительно шустро работать с GPIO, а у меня нет девборд с "жирными" STM32, где есть FSMC, нужно как-то имитировать эту самую FSMC. Я попробовал два способа: с таймером и с DMA (код поместил в репозиторий stm32samples, директории GPIO_TIM и DMA_GPIO).

Итак, с таймером все просто. Настраиваем таймер:
void timgpio_init(){
	// init TIM2 & DMA1ch2 (TIM2UP)
	rcc_periph_clock_enable(RCC_TIM2);
	rcc_periph_clock_enable(RCC_DMA1);
	timer_reset(TIM2);
	// timer have frequency of 1MHz
	timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
	// 72MHz main freq, 2MHz for timer
	TIM2_PSC = 0;
	TIM2_ARR = 35;
	TIM2_DIER = TIM_DIER_UDE | TIM_DIER_UIE;
	nvic_enable_irq(NVIC_TIM2_IRQ);
}

Заводим локальный буфер, куда сбрасываем данные, передаваемые на ноги GPIO (я использовал младшие 8 бит PA) и перед отправлением заполняем его и выставляем счетчики:
void timgpio_transfer(uint8_t *databuf, uint32_t length){
	transfer_complete = 0;
	memcpy(addr, databuf, length);
	len = length;
	curidx = 0;
	TIM2_CR1 |= TIM_CR1_CEN; // run timer
}

Ну, а сам таймер отправляет на ноги GPIO очередную порцию данных:
void tim2_isr(){
	if(TIM2_SR & TIM_SR_UIF){ // update interrupt
		GPIOA_ODR = addr[curidx];
		if(++curidx >= len){
			TIM2_CR1 &= ~TIM_CR1_CEN;
			transfer_complete = 1;
		}
		TIM2_SR = 0;
	}
}


С прямым доступом к памяти немного по-другому. Сначала настраиваем таймер и ПДП:
void dmagpio_init(){
	// init TIM2 & DMA1ch2 (TIM2UP)
	rcc_periph_clock_enable(RCC_TIM2);
	rcc_periph_clock_enable(RCC_DMA1);
	timer_reset(TIM2);
	// timer have frequency of 1MHz
	timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
	// 72MHz div 18 = 4MHz
	TIM2_PSC = 0; // prescaler is (div - 1)
	TIM2_ARR = 1; // 36MHz (6.25)
	TIM2_DIER = TIM_DIER_UDE;// | TIM_DIER_UIE;
	dma_channel_reset(DMA1, DMA_CHANNEL2);
	// mem2mem, medium prio, 8bits, memory increment, read from mem, transfer complete en
	DMA1_CCR2 = DMA_CCR_PL_MEDIUM | DMA_CCR_MSIZE_16BIT |
		DMA_CCR_PSIZE_16BIT | DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE ;
	nvic_enable_irq(NVIC_DMA1_CHANNEL2_IRQ);
	// target address:
	DMA1_CPAR2 = DMAGPIO_TARGADDR;
	DMA1_CMAR2 = (uint32_t) gpiobuff;
}

Далее для передачи данных копируем их в локальный буфер и пинаем таймер с ПДП:
void dmagpio_transfer(uint8_t *databuf, uint32_t length){
	while(DMA1_CCR2 & DMA_CCR_EN);
	transfer_complete = 0;
	DMA1_IFCR = 0xff00; // clear all flags for ch2
	// buffer length
	DMA1_CNDTR2 = length;
	uint32_t i;
	for(i = 0; i < length; ++i) gpiobuff[i] = databuf[i];
	TIM2_CR1 |= TIM_CR1_CEN; // run timer
	DMA1_CCR2 |= DMA_CCR_EN;
}

Обработчик прерывания или пишет "Фигвамушки", если возникает ошибка (а у меня поначалу и были ошибки, когда я пытался восьмибитный буфер в 16-битный регистр запихнуть, надо быть внимательней), или же выставляет флаг окончания передачи и отрубает уже ненужные функции:
void dma1_channel2_isr(){
	if(DMA1_ISR & DMA_ISR_TCIF2){
		transfer_complete = 1;
		// stop timer & turn off DMA
		TIM2_CR1 &= ~TIM_CR1_CEN;
		DMA1_CCR2 &= ~DMA_CCR_EN;
		DMA1_IFCR = DMA_IFCR_CTCIF2; // clear flag
	}else if(DMA1_ISR & DMA_ISR_TEIF2){
		P("Error\n");
		DMA1_IFCR = DMA_IFCR_CTEIF2;
		TIM2_CR1 &= ~TIM_CR1_CEN;
		DMA1_CCR2 &= ~DMA_CCR_EN;
	}
}

Вчера я часа 3 вечером убил, да еще и сегодня где-то с час, пока наконец оживил ПДП. А все было из-за того, что я вместо ((uint32_t)&GPIOA_ODR) в DMAGPIO_TARGADDR запихнул непосредственно GPIOA_ODR (т.е. значение битов в порту).

Результаты неутешительные: хоть и есть режим GPIO под гордым названием GPIO_MODE_OUTPUT_50_MHZ, на деле все не так. Наибольшая скорость, которую я достиг с ПДП, составляла около 6.25МГц (т.к. у меня китайский клон Saleae Logick, ему я на таких скоростях не поверил, что, кстати, сделал правильно: брехал он изрядно, а посмотрел на осциллографе). У пинания портов GPIO в прерывании таймера по понятным причинам (обработчик прерывания длится дольше периода таймера) скорость еще меньше: не выше 1.1МГц.
Таким образом, передавать данные по параллельной шине с STM32F103 на скоростях выше 6МГц можно и не рассчитывать!
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

May 2025

S M T W T F S
    123
45678910
11121314151617
1819202122 2324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jun. 1st, 2025 12:00 pm
Powered by Dreamwidth Studios