Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Can в STM32F103RBT6
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Elcarnado
Здравствуйте! Начал осваивать stm и интерфейс can, пытаюсь осуществить передачу по данному интерфейсу, но пока тщетно. Для инициализации использую стандартные API-функции в программе CooCox. Заметил такую вещь: регистр MCR, отвечающий за режимы работы Can-интерфейса, не изменяет своего значения: то есть код вида "CANx->MCR = CANx->MCR | 0x0001" никак не влияет на состояние регистра. Пробовал разобраться по примеру, приведенному в CooCox, но еще больше запутался rolleyes.gif В этом примере никак не инициализируется порт для CAN, не делается ремаппинг и AFIO и не используется регистр MCR (он нужен для переключения режимов Sleep->Normal->Initialisation).
Мой листинг настройки Can:
CODE
void Init_Can(void)
{
// Инициализация порта
RCC_APB2PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); // включаем тактирование CAN1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // включаем тактирование AFIO
GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE); // Переносим Can1 на PB8, PB9
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // включаем тактирование порта B

// CAN RX pin PB.8 input push pull
GPIO_InitTypeDef INIT_GPIO_B; // Объявляем структуру для инициализации порта
GPIO_StructInit(&INIT_GPIO_B); // заполняем дефолтными значениями
INIT_GPIO_B.GPIO_Mode = GPIO_Mode_IPU; // Режим - вход Pull-up (см. RM0041 p.154)
INIT_GPIO_B.GPIO_Pin = GPIO_Pin_8; // Настраиваем пин 8 порта B
INIT_GPIO_B.GPIO_Speed = GPIO_Speed_10MHz; // Скорость изменения пина
GPIO_Init(GPIOC, &INIT_GPIO_B); // Загрузка структуры настройки

// CAN TX pin PB.9 Alternative function Push-pull
INIT_GPIO_B.GPIO_Mode = GPIO_Mode_AF_PP; // Режим - Alternative Push-pull
INIT_GPIO_B.GPIO_Pin = GPIO_Pin_9; // Настраиваем пин 9 порта B
INIT_GPIO_B.GPIO_Speed = GPIO_Speed_10MHz; // Скорость изменения пина
GPIO_Init(GPIOC, &INIT_GPIO_B); // Загрузка структуры настройки

//Переход в режим настройки CAN
uint8_t ini = CAN_OperatingModeRequest(CAN1, CAN_OperatingMode_Initialization);
CAN_InitTypeDef CAN1_InitStruct;
CAN_StructInit(&CAN1_InitStruct);
CAN1_InitStruct.CAN_BS1 = CAN_BS1_3tq;
CAN1_InitStruct.CAN_BS2 = CAN_BS2_2tq;
CAN1_InitStruct.CAN_Prescaler = 24; //250 kbit/s (Prescaler = 6*10^6 / Speed)
CAN_Init(CAN1, &CAN1_InitStruct);

// Переход в нормальный режим работы CAN
uint8_t normal = CAN_OperatingModeRequest(CAN1, CAN_OperatingMode_Normal);

Данный код никак не влияет на состояние CAN-интерфейса и он продолжает спокойно пребывать в режиме SLEEP.
Функция CAN_OperatingModeRequest() взята из файла stm32f10x_can.h.
Помогите, пожалуйста, разобраться.
Elcarnado
Так-с... С этой проблемкой воде разобрался (понадобился незамыленный взгляд другого человека). Вместо
RCC_APB2PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
должно быть конечно же
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
SasaVitebsk
Вроде всё у вас нормально.
Я правда с 105 работал. Я ещё фильтра настраивал, но вроде это не принципиально

CODE
/* CAN cell init */
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
CAN_InitStructure.CAN_Prescaler = 16; // 250 кбит
CAN_Init(CAN1, &CAN_InitStructure);

/* CAN filter 0 init */
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh= (PCAN_ID_PC1_FLT>>13) & 0xffff;
CAN_FilterInitStructure.CAN_FilterIdLow= (PCAN_ID_PC1_FLT<<3) & 0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= (PCAN_ID_PC1_MSK>>13) & 0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdLow= (PCAN_ID_PC1_MSK<<3) & 0xffff;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
Elcarnado
Эх... Кан все-равно не работает ((( Объявляю переменную типа CanTxMsg, заполняю её поля и отсылаю командой CanTransmit(). На пинах порта после выполнения команды висит +3v и никаких телодвижений.... Вот код инициализации и отправки сообщения:
Код
        CanTxMsg msg;                         // Объявляем переменную для отправки
    msg.StdId = 0x00;                    // Стандартный ID сообщения
    msg.ExtId = 0x1234;                 // Расширенный ID сообщения
    msg.IDE = CAN_ID_EXT;           // Использовать расширенный ID
    msg.RTR = CAN_RTR_DATA;     // Уже забыл что это, но мне сейчас наполнение фрейма вообще не важно
    msg.DLC = 2;                            // Отправляем 2 байта
    msg.Data[0] = 0xDE;                  // байт 1
    msg.Data[1] = 0xCA;                 // байт 2

    uint8_t TR = CAN_Transmit(CAN1, &msg); // Отправляем сообщение
Elcarnado
Здравствуйте! После отправки сообщения проверяю в бесконечном цикле статус сообщения функцией CAN_TransmitStatus. Заметил, что эта функция всегда возвращает статус сообщения как "в ожидании" (CAN_TxStatus_Pending) и сообщение никогда не отправляется. Мне кажется, я что-то упустил при настройке контроллера либо самого CAN. Подскажите пожалуйста, что еще нужно посмотреть...
Golikov A.
вопрос в том есть ли приемники сообщения? если на линии никого нет, то никто не выставит бит что сообщение принято, и оно никогда не отправиться...
Elcarnado
Цитата(Golikov A. @ Mar 7 2013, 14:18) *
вопрос в том есть ли приемники сообщения? если на линии никого нет, то никто не выставит бит что сообщение принято, и оно никогда не отправиться...

А вот об этом я как раз и не подумал... Спасибо! Будет теперь над чем поразмыслить в выходные. Думаю, именно поэтому, когда я выставляю LoopMode (когда TX на RX замыкается), то сообщение вроде бы как отправляется (не уверен по причине того, что осциллографом я так ничего пока и не увидел, но функция CAN_TransmitStatus возвращает значение "отправлено").
А подскажите пожалуйста, необходимо ли на линии два резистора между RX и TX или достаточно будет одного?
Golikov A.
Все зависит. Есть стандарт и рекомендации лучше им следовать. На коротких линиях работает и без резистора. Но лучше делать хорошо, а плохо оно само получится. Учитывайте что очень много чего от вас спрятано железной реализацией кана, проверки контрольных сумм, повторные отправки и так далее.. И если на линии будут сложности в условиях лаборатории вы их сможете и не заметить, а поставив на реальный объект удивитесь. Те кто развивает кан потратили не мало времени на выработку оптимальных рекомендаций и им лучше следовать...

кстати в луп моде вроде бы подтверждения отправки не выставляются, но я могу ошибаться, нет описания под рукой. Может внутри процессора выставляются...
Elcarnado
Доброго вечера! Снова прошу вашей помощи. Интерфейс КАН заработал и на осциллографе даже сигналы видны (сколько радости то было rolleyes.gif ). Помогите настроить прерывания по приему сообщения (Интерфейс работает в режиме LoopMode, - хочу получить прерывание от своих же пакетов). Вот как я настраиваю NVIC:
Код
void Init_NVIC(void)
    {
    __enable_irq ();                                //Разрешить глобальные прерывания

    NVIC_InitTypeDef nvic;
    nvic.NVIC_IRQChannel =  CAN1_RX1_IRQn;            //Прерывание по получению сообщения
    nvic.NVIC_IRQChannelCmd = ENABLE;
    nvic.NVIC_IRQChannelPreemptionPriority = 1;
    nvic.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&nvic);                                //Инициализация контроллера прерываний

    CAN_ITConfig(CAN1,CAN_IT_TME| CAN_IT_FMP0|CAN_IT_FMP1,ENABLE); // Настройка event для КАН-интерфейса.

Пробовал также включать прерывания по SLEEP и WAKE UP, но тщетно. Меня терзают смутные сомнения насчет правильности имени обработчика прерывания, у меня обработка происходит в функции с именем
Код
void CAN1_RX1_IRQHandler(void) {...}

Имя функции взял из файла startup_stm32f10x_md. Подскажите пожалуйста, где может быть ошибка?
Golikov A.
посмотрите в таблице прерываний
CAN1_RX1_IRQn
какую функцию вызывает.
так вы определитесь с функцией...

потом
void CAN1_RX1_IRQHandler(void) {...}
в зависимости от среды надо проверить иногда требуется обозначить что это функция прерывание. либо прагмой либо еще как... В проекте есть еще хоть какие -то прерывания? вы их так же вызываете?

Проверьте регистры КАН, там может быть глобальный флаг на разрешение-запрещение всех прерываний

Я бы проверил значение регистров после инициализации, и сравнил с тем что там должно быть по описанию. Библиотеки - это весело и здорово, но их тоже люди пишут, а читать описание как ими пользоваться у нас не в почете...
Elcarnado
Цитата(Golikov A. @ Mar 12 2013, 19:12) *
посмотрите в таблице прерываний
CAN1_RX1_IRQn
какую функцию вызывает.
так вы определитесь с функцией...

потом
void CAN1_RX1_IRQHandler(void) {...}
в зависимости от среды надо проверить иногда требуется обозначить что это функция прерывание. либо прагмой либо еще как... В проекте есть еще хоть какие -то прерывания? вы их так же вызываете?

Проверьте регистры КАН, там может быть глобальный флаг на разрешение-запрещение всех прерываний

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


Спасибо за советы! Вопрос от новичка: а где посмотреть таблицу прерываний? Я нашел только список прерываний с номерами в файле stm32f10x.h:
CODE
ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */
USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */
USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */
CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */
CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */
TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */
TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */
TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
TIM4_IRQn = 30, /*!< TIM4 global Interrupt */
I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */
I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */
SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
SPI2_IRQn = 36, /*!< SPI2 global Interrupt */
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */

и список обработчиков прерываний в файле startup_stm32f10x_md.c:

CODE
void WEAK Reset_Handler(void);
void WEAK NMI_Handler(void);
void WEAK HardFault_Handler(void);
void WEAK MemManage_Handler(void);
void WEAK BusFault_Handler(void);
void WEAK UsageFault_Handler(void);
void WEAK SVC_Handler(void);
void WEAK DebugMon_Handler(void);
void WEAK PendSV_Handler(void);
void WEAK SysTick_Handler(void);
void WEAK WWDG_IRQHandler(void);
void WEAK PVD_IRQHandler(void);
void WEAK TAMPER_IRQHandler(void);
void WEAK RTC_IRQHandler(void);
void WEAK FLASH_IRQHandler(void);
void WEAK RCC_IRQHandler(void);
void WEAK EXTI0_IRQHandler(void);
void WEAK EXTI1_IRQHandler(void);
void WEAK EXTI2_IRQHandler(void);
void WEAK EXTI3_IRQHandler(void);
void WEAK EXTI4_IRQHandler(void);
void WEAK DMA1_Channel1_IRQHandler(void);
void WEAK DMA1_Channel2_IRQHandler(void);
void WEAK DMA1_Channel3_IRQHandler(void);
void WEAK DMA1_Channel4_IRQHandler(void);
void WEAK DMA1_Channel5_IRQHandler(void);
void WEAK DMA1_Channel6_IRQHandler(void);
void WEAK DMA1_Channel7_IRQHandler(void);
void WEAK ADC1_2_IRQHandler(void);
void WEAK USB_HP_CAN1_TX_IRQHandler(void);
void WEAK USB_LP_CAN1_RX0_IRQHandler(void);
void WEAK CAN1_RX1_IRQHandler(void);
void WEAK CAN1_SCE_IRQHandler(void);
void WEAK EXTI9_5_IRQHandler(void);
void WEAK TIM1_BRK_IRQHandler(void);
void WEAK TIM1_UP_IRQHandler(void);
void WEAK TIM1_TRG_COM_IRQHandler(void);
void WEAK TIM1_CC_IRQHandler(void);
void WEAK TIM2_IRQHandler(void);
void WEAK TIM3_IRQHandler(void);
void WEAK TIM4_IRQHandler(void);
void WEAK I2C1_EV_IRQHandler(void);
void WEAK I2C1_ER_IRQHandler(void);
void WEAK I2C2_EV_IRQHandler(void);
void WEAK I2C2_ER_IRQHandler(void);
void WEAK SPI1_IRQHandler(void);
void WEAK SPI2_IRQHandler(void);
void WEAK USART1_IRQHandler(void);
void WEAK USART2_IRQHandler(void);
void WEAK USART3_IRQHandler(void);
void WEAK EXTI15_10_IRQHandler(void);
void WEAK RTCAlarm_IRQHandler(void);
void WEAK USBWakeUp_IRQHandler(void);


Чисто теоретически можно догадаться, что к чему, но вот где посмотреть, кто кого вызывает - не могу понять...
P.S. Была бы документация на эту библиотеку - с удовольствием почитал бы laughing.gif
Golikov A.
startup_stm32f10x_md.c - близко, почти горячоsm.gif...



вы нашли описание, прототипы функций. А надо найти вызовы%)...
CAN1_SCE_IRQHandler - вот это что за прерывание?

доберусь до работы завтра погляжу что там не так
Elcarnado
Цитата(Golikov A. @ Mar 13 2013, 17:01) *
startup_stm32f10x_md.c - близко, почти горячоsm.gif...



вы нашли описание, прототипы функций. А надо найти вызовы%)...
CAN1_SCE_IRQHandler - вот это что за прерывание?

доберусь до работы завтра погляжу что там не так


С прерывания более-менее разобрался. Я включал и опрашивал не то прерывание. Для прерывания по приему данных необходимо включать вот этот вектор в NVIC:
USB_LP_CAN1_RX0_IRQn
Разрешать вот это событие в Can:
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
И вызывать вот этот обработчик:
void USB_LP_CAN1_RX0_IRQHandler(void).

Теперь другая печаль wacko.gif В обработчике прерывания я в глобальную переменную записываю 1. А в основной программе зажигаю светодиод по этой единичке. Так вот, если программу выполнять пошагово через дебаггер, то в прерывание я попадаю и светодиод благополучно загорается. А если загрузить эту программу на выполнение в реальном времени, то светодиод не загорается. Может, посоветуете чего по этому поводу? help.gif
adnega
Цитата(Elcarnado @ Mar 13 2013, 19:32) *
С прерывания более-менее разобрался. Я включал и опрашивал не то прерывание. Для прерывания по приему данных необходимо включать вот этот вектор в NVIC:
USB_LP_CAN1_RX0_IRQn
Разрешать вот это событие в Can:
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
И вызывать вот этот обработчик:
void USB_LP_CAN1_RX0_IRQHandler(void).

Теперь другая печаль wacko.gif В обработчике прерывания я в глобальную переменную записываю 1. А в основной программе зажигаю светодиод по этой единичке. Так вот, если программу выполнять пошагово через дебаггер, то в прерывание я попадаю и светодиод благополучно загорается. А если загрузить эту программу на выполнение в реальном времени, то светодиод не загорается. Может, посоветуете чего по этому поводу? help.gif

Приписать volatile к переменной.
Golikov A.
почему USB?

volatile - возможно, но почему в дебагере работает? Меняется оптимизация? Ведь если переменная была с оптимизирована в рабочем варианте, то она будет с оптимизирована и в дебагере, и наоборот. Думаю либо прерывание вызывается так часто что вы в обычном режиме не попадаете в нормальный цикл, то есть при выполнении никогда не выходите из функции прерывания...
_Артём_
Цитата(Golikov A. @ Mar 13 2013, 18:51) *
почему USB?

volatile - возможно, но почему в дебагере работает?

Может в отладчике используется Debug, а прошивается Release?
Golikov A.
Количество странностей заставило меня все таки открыть доку и проектик.

и так список векторов прерываний
в файлике
startup_stm32f10x_md.s
учитывая стилистку и имена вызываемых функций у вас такое должно быть
они там просто идут списком.

описания функций можно правда не чем не предварять, просто
void vector_func(void), видать ядро берет на себя все правильные возвраты...

дальше КАН имеет 2 входных буфера и если внимательно поглядеть то есть
CAN_TX_interrupt
CAN_RX0_interrupt
CAN_RX1_interrupt
сообщения приходят в 0, если он занят то они приходят в 1 буфер.
ваша первая попытка поймать сообщение в 1 буфере потому и не сработала, и потом сработала вторая попытка поймать сообщение в 0. По идее необходимо обрабатывать оба буфера и 0 и 1

Ответ на вопрос почему USB. Потому что так чудно получилось что на 19 и 20 канале прерываний у этих процессоров и USB и CAN - вот же! Так что если все по уму то у вас надо
1. сделать реакцию не только на RX0 но и на RX1,

2. Под прерывание от RX0 проверить что прерывание точно от кана, а то добавите потом USB, и будете думать кто вас дернул...

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

4. Опять же прочитать мануал чтобы понять что да как работает. Если вы в кэйле добавить в проект отладочную информацию, то тыкая правой кнопкой мыши в функции сможете из меню выбирать пункт показать их объявление. Думаю имеет смысл прочитать реализацию функций типа NVIC_Init чтобы понимать точно что происходит, где какие флаги ставятся, и как что потом будет работать!



http://easyelectronics.ru/arm-uchebnyj-kur...preryvanij.html
ИМХО имеет смысл ознакомиться!
Elcarnado
Цитата(adnega @ Mar 13 2013, 18:30) *
Приписать volatile к переменной.

Volatile был изначально.
Golikov A.
ну тогда вы просто не выпадаете из прерывания в основной цикл где можете по флажку включить диод.
Elcarnado
Цитата(Golikov A. @ Mar 14 2013, 09:35) *
ну тогда вы просто не выпадаете из прерывания в основной цикл где можете по флажку включить диод.


Спасибо большое за советы! Поставил включение светодиода в прерывание - все-равно не включается. Прерывания включил и RX0 и RX1: в RX1 не попадаю, т.к. отправляю всего одно сообщение, - в принципе логично и это радует. Почитал про флаги для выхода из прерывания: в прерывания мы залетаем, когда счетчик принятых сообщений не равен нулю, выставляя флаг RFOM0 в регистре CAN_RF0R, аппаратно декрементируется этот счетчик. Посмотрел регистр в дебаге - счетчик на входе в прерывании равен 1, после чтения сообщения - 0, здесь все нормально. Наткнулся на непонятную мне запись в Reference manual (RM0008, страница 639, выбор режима работы CAN):

Bit 31 SILM: Silent mode (debug)
0: Normal operation
1: Silent Mode
Bit 30 LBKM: Loop back mode (debug)
0: Loop Back Mode disabled
1: Loop Back Mode enabled

Это значит, что данные режимы (а у меня CAN как раз в режиме Loop back) доступны только в дебаге или как? Помогите расшифровать эту запись, пожалуйста.
Golikov A.
строго говоря это режим для отладки, как и сайлент мод, а вот может ли как то процессор отличить в каком он режиме в рабочем или отладке хрен знает, всегда думал что режимы не отличимы, но если может тогда понятно что происходит, без дебага к вам не возвращается ваше сообщение, его никто не принимает, и не возникает прерывания...
Elcarnado
Добрый день! Наконец-то удалось подружить два устройства по СAN-интерфейсу. Основной момент был в том, что во время дебага при приеме сообщения я влетал в прерывание по FIFO0, а во время выполнения программы в режиме реального времени контроллер получал прерывание от FIFO1 (проверял светодиодами). Спасибо всем большое за советы!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.