Хочу сказать спасибо всем комментаторам моих предыдущих статей о знакомстве с программированием микропроцессора (МК) Artery AT32F403A. Что-то возможно возьму на заметку. Что касаемо стабильности работы прошивки, то сообщу, в полевых испытаниях пройдено более 600 км и более 21 часа работы, без сбоев в работе канбаса и приложения. Но нет, вру. Один сбой был. При выходе из сна магнитолы, канбас "зависал", так как он по питанию подключен к магнитоле. Но эта проблема была решена временной задержкой при старте инициализации.
int main(void) {
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
system_clock_config();
delay_init();
delay_ms(2000);
init_usb_device();
****** дальнейший код
Топорно? Не спорю, возможно. Но работает, и на основной функционал не влияет. От слова совсем. Магнитола дольше включается.
Так же хочу заметить, что все четыре статьи нужно читать последовательно, что бы не потерять нить обсуждения, так как я не ставил задачу делать самостоятельные статьи, а разделил для удобства переваривания.
Что ещё интересного и нужного.
Отправка данных в USART. Код примеров вы можете посмотреть AT32F403A_407_Firmware_Library_V2.1.4\project\at_start_f403a\examples\usart.
Рассматривать пример я не буду, потому что у себя в проекте я использовал только одну функцию передачи. Но сложностей там тоже никаких нет, вы справитесь.
uint8_t LIN_Buffer_C6[7] = {0};
********
while(tx_counter < 7) {
while(usart_flag_get(USART3, USART_TDBE_FLAG) == RESET);
usart_data_transmit(USART3, LIN_Buffer_C6[tx_counter++]);
}
tx_counter = 0;
Вот и весь код отправки пакета из 7 байт. Код ставится в любом удобном для вас месте.
Порты ввода/вывода. Собственно они инициализируются аналогично инициализации LED в первой статье. Единственное, нужно править строку GPIO_Init.gpio_mode в зависимости от потребностей, её значение может принимать GPIO_MODE_INPUT или GPIO_MODE_OUTPUT.
gpio_init_type GPIO_Init;
GPIO_Init.gpio_mode = GPIO_MODE_INPUT;
GPIO_Init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_6;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
GPIO_Init.gpio_mode = GPIO_MODE_OUTPUT;
GPIO_Init.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
GPIO_Init.gpio_pull = GPIO_PULL_NONE;
GPIO_Init.gpio_pins = GPIO_PINS_7;
GPIO_Init.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init(GPIOC, &GPIO_Init);
gpio_bits_reset(GPIOC, GPIO_PINS_7); // Напряжение низкого уровня
gpio_bits_set(GPIOC, GPIO_PINS_7); // Напряжение высокого уровня
Проверка на состояние порта
if (gpio_output_data_bit_read(GPIOC, GPIO_PINS_7)) {
// на выводе высокий уровень
} else {
// на выводе низкий уровень
}
Добавим кольцевой буфер
uint32_t ptrWriteUserTxBufferFS = 0 ;
uint32_t ptrReadUserTxBufferFS = 0 ;
uint8_t CDC_add_buf_to_transmit(uint8_t* Buf, uint16_t Len) {
uint16_t _cnt = Len ;
while(_cnt) {
UserTxBufferFS[ptrWriteUserTxBufferFS] = *Buf ;
ptrWriteUserTxBufferFS++;
Buf++ ;
ptrWriteUserTxBufferFS %= APP_TX_DATA_SIZE ;
_cnt--;
}
return(0);
}
uint8_t CDC_periodic_callback(void) {
uint32_t buffptr;
uint32_t buffsize;
if(ptrReadUserTxBufferFS != ptrWriteUserTxBufferFS) {
if(ptrReadUserTxBufferFS > ptrWriteUserTxBufferFS) { /* Rollback */
buffsize = APP_TX_DATA_SIZE - ptrReadUserTxBufferFS;
} else {
buffsize = ptrWriteUserTxBufferFS - ptrReadUserTxBufferFS;
}
buffptr = ptrReadUserTxBufferFS;
if (usb_vcp_send_data(&usb_core_dev, (uint8_t*)&UserTxBufferFS[buffptr], buffsize) == SUCCESS) {
ptrReadUserTxBufferFS += buffsize;
if (ptrReadUserTxBufferFS == APP_TX_DATA_SIZE) {
ptrReadUserTxBufferFS = 0;
}
}
}
return(0);
}
Отправляем в кольцевой буфер после обработки сигнала с каншины
CDC_add_buf_to_transmit(CDC_Tx2_Buffer, 0x0010); // 10hex - длина пакета
Вызываем данные с кольцевого буфера в теле main
while(1) {
CDC_periodic_callback(); // из буфера
/*.....*/
}
WatchDog или перезагружаем программу "на ходу"
Очень полезная функция, в случае, если ваша программа по каким-то причинам зависла в процессе выполнения. Можно её перезапустить, лишив питания плату, или через таймер watchdog. Его функции простые, если его счётчик доходит до 300 (время 300 мс), то программа перезагружается заново. Что бы этого не случилось в нормальном режиме работы программы, его необходимо сбрасывать. Настройка очень простая
void ini_watchdog(void) {
if(crm_flag_get(CRM_WDT_RESET_FLAG) != RESET) {
/* reset from wdt */
crm_flag_clear(CRM_WDT_RESET_FLAG);
}
/* disable register write protection */
wdt_register_write_enable(TRUE);
/* set the wdt divider value */
wdt_divider_set(WDT_CLK_DIV_4);
/* set reload value
timeout = reload_value * (divider / lick_freq ) (s)
lick_freq = 40000 Hz
divider = 4
reload_value = 3000
timeout = 3000 * (4 / 40000 ) = 0.3s = 300ms
*/
wdt_reload_value_set(3000 - 1);
/* reload wdt counter */
wdt_counter_reload();
/* enable wdt */
wdt_enable();
}
int main(void) {
system_clock_config();
/* get system clock */
crm_clocks_freq_get(&crm_clocks_freq_struct);
/* config nvic priority group */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
ini_watchdog();
/*...какой-то код.....*/
while(1) {
/* reload wdt counter */
wdt_counter_reload();
/*...какой-то код......*/
}
}
На этом пожалуй всё.
Матёрые программисты микроконтроллеров простите. Я просто делился своими знаниями, полученными в ходе работы. Так как в интернете нет почти информации об этом МК. А сейчас есть хоть что-то.
Надеюсь мои статьи о программировании МК AT32F403A помогут кому-то решиться перейти с STM32 на AT32, и осуществить переход с минимумом головной боли, или помогут молодым программистам в изучении. Всем пока, ушёл дальше писать на Java