Compare commits
2
Commits
Dev
..
ai-context
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9bcee430b | ||
|
|
8b593c1849 |
@@ -0,0 +1 @@
|
|||||||
|
b939fe52ce9bb7821057ca91996797104da48e80
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# 🤖 Технический контекст проекта (Сгенерировано ИИ)
|
||||||
|
|
||||||
|
### README для репозитория
|
||||||
|
|
||||||
|
**1. Краткое назначение проекта:**
|
||||||
|
Проект предназначен для разработки и поддержки набора файлов, необходимых для работы с определённой системой или платформой. Конкретное назначение зависит от содержимого файлов в проекте и должно быть уточнено в соответствующих комментариях и документации.
|
||||||
|
|
||||||
|
**2. Тип стека:**
|
||||||
|
Тип стека не определён из-за отсутствия информации о содержимом файлов. Возможно, это набор скриптов, конфигурационных файлов или исходников для конкретной платформы/языка программирования.
|
||||||
|
|
||||||
|
**3. Архитектурный разбор:**
|
||||||
|
Для более точного архитектурного разбора необходимо изучить содержимое папок и файлов в проекте. Без этой информации можно предположить следующее:
|
||||||
|
* Папки содержат различные компоненты системы или приложения. Названия папок могут указывать на их назначение (например, `src` для исходных кодов, `config` для конфигурационных файлов).
|
||||||
|
* Файлы в папках выполняют определённые функции, связанные с работой системы. Например, файлы в папке `src` могут содержать код, реализующий логику работы приложения, а файлы в папке `config` — настройки и параметры конфигурации.
|
||||||
|
|
||||||
|
Рекомендуется изучить структуру папок и содержимое файлов для более точного понимания архитектуры проекта.
|
||||||
|
|
||||||
|
<!-- USER_CUSTOM_CONTEXT_START -->
|
||||||
|
# ✍️ Заметки разработчика
|
||||||
|
*Допишите сюда свои требования, и ИИ учтет их при следующем запуске*
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#ifndef DS_SN65HVD230_H
|
|
||||||
#define DS_SN65HVD230_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef STM32G030xx
|
|
||||||
#include "stm32g0xx_hal.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef STM32G0B1xx
|
|
||||||
#include "stm32g0xx_hal.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Управляющий дескриптор для STM32G0 */
|
|
||||||
typedef struct {
|
|
||||||
FDCAN_HandleTypeDef *hfdcan; // Указатель на аппаратный FDCAN в STM32G0
|
|
||||||
} SN65HVD230_t;
|
|
||||||
|
|
||||||
/* Унифицированная структура кадра (Классический CAN-режим на FDCAN) */
|
|
||||||
typedef struct {
|
|
||||||
uint32_t Identifier; // ID пакета (11 или 29 бит)
|
|
||||||
uint32_t IdType; // Тип: FDCAN_STANDARD_ID или FDCAN_EXTENDED_ID
|
|
||||||
uint32_t TxFrameType; // Тип кадра: FDCAN_DATA_FRAME или FDCAN_REMOTE_FRAME
|
|
||||||
uint32_t DataLength; // Количество байт данных: от FDCAN_DLC_BYTES_0 до FDCAN_DLC_BYTES_8
|
|
||||||
uint8_t Data[8]; // Буфер данных (макс 8 байт для классического CAN)
|
|
||||||
} CAN_Message_t;
|
|
||||||
|
|
||||||
/* Прототипы функций управления */
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Init(SN65HVD230_t *node, FDCAN_HandleTypeDef *hfdcan_handle);
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Start(SN65HVD230_t *node);
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Stop(SN65HVD230_t *node);
|
|
||||||
|
|
||||||
/* Функции отправки и приема */
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Transmit(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms);
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Receive(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // DS_SN65HVD230_H
|
|
||||||
@@ -1,176 +1,2 @@
|
|||||||
# SN65HVD230
|
# SN65HVD230
|
||||||
|
|
||||||
### Драйвер трансивера SN65HVD230 для STM32G0 (FDCAN)
|
|
||||||
|
|
||||||
Легковесная, объектно-ориентированная библиотека на Си для работы с CAN-трансивером **SN65HVD230** (на базе плат типа MCU-230 / CJMCU-230) через аппаратный модуль **FDCAN** микроконтроллеров семейства **STM32G0**.
|
|
||||||
|
|
||||||
Библиотека оптимизирована для работы в режиме классического CAN (Classic CAN) на максимальной скорости, так как на используемом модуле пин управления энергосбережением (`Rs`) аппаратно подтянут к GND.
|
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
### 📌 Особенности реализации
|
|
||||||
|
|
||||||
* **Чистый ООП-стиль на Си**: вся работа идет через дескриптор устройства `SN65HVD230_t`.
|
|
||||||
* **Специализировано под STM32G0**: код очищен от лишних макросов препроцессора и завязан строго на архитектуру модуля FDCAN.
|
|
||||||
* **Безопасность памяти**: полное отсутствие динамического выделения памяти (`malloc`).
|
|
||||||
* **Контроль таймаутов**: функции отправки и приема снабжены блокирующими тайм-аутами для предотвращения зависания контроллера при сбоях на физическом уровне шины.
|
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
### 🛠 Настройка периферии в STM32CubeMX
|
|
||||||
|
|
||||||
Для корректной работы библиотеки настройте модуль FDCAN в графическом конфигураторе:
|
|
||||||
|
|
||||||
1. В разделе **Connectivity** выберите **FDCAN1**.
|
|
||||||
2. Установите режим **Operating Mode** в значение **Architecture**.
|
|
||||||
3. **Настройка тактирования (Bit Timings)**:
|
|
||||||
* Настройте параметры `Nominal Prescaler`, `Time Seg1` и `Time Seg2` под требуемую скорость вашей сети (например, 250 или 500 кбит/с).
|
|
||||||
* Режим `Frame Format` установите в **Classic CAN**.
|
|
||||||
4. Вкладка **NVIC Settings**:
|
|
||||||
* Включите прерывание **FDCAN1 interrupt 0** (необходимо для работы системы уведомлений и прерываний).
|
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
### 🔌 Схема подключения (MCU-230 <-> STM32G0)
|
|
||||||
|
|
||||||
Контакт модуля MCU-230
|
|
||||||
|
|
||||||
Контакт STM32G0
|
|
||||||
|
|
||||||
Описание
|
|
||||||
|
|
||||||
**3V3**
|
|
||||||
|
|
||||||
3.3V
|
|
||||||
|
|
||||||
Питание модуля (от шины МК)
|
|
||||||
|
|
||||||
**GND**
|
|
||||||
|
|
||||||
GND
|
|
||||||
|
|
||||||
Общая земля
|
|
||||||
|
|
||||||
**CTX**
|
|
||||||
|
|
||||||
FDCAN1\_TX
|
|
||||||
|
|
||||||
Линия передачи данных (настраивается в CubeMX)
|
|
||||||
|
|
||||||
**CRX**
|
|
||||||
|
|
||||||
FDCAN1\_RX
|
|
||||||
|
|
||||||
Линия приема данных (настраивается в CubeMX)
|
|
||||||
|
|
||||||
**CANH**
|
|
||||||
|
|
||||||
Линия CAN\_H
|
|
||||||
|
|
||||||
Прямой дифференциальный сигнал шины
|
|
||||||
|
|
||||||
**CANL**
|
|
||||||
|
|
||||||
Линия CAN\_L
|
|
||||||
|
|
||||||
Инверсный дифференциальный сигнал шины
|
|
||||||
|
|
||||||
⚠️ **Важное замечание по терминатору 120 Ом:**
|
|
||||||
На плате MCU-230 уже распаян SMD-резистор `121` (120 Ом).
|
|
||||||
|
|
||||||
* Если в вашей тестовой сети всего **два устройства** — оставьте его.
|
|
||||||
* Если вы подключаете этот модуль к **готовой существующей сети**, где на концах уже установлены терминаторы — обязательно **выпаяйте резистор 120 Ом** с платы модуля, чтобы не просаживать импеданс шины.
|
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
### 🚀 Быстрый старт (Пример использования)
|
|
||||||
|
|
||||||
Добавьте файлы `sn65hvd230_g0.h` и `sn65hvd230_g0.c` в свой проект. Скопируйте следующую логику в файл `main.c`:
|
|
||||||
|
|
||||||
c
|
|
||||||
|
|
||||||
#include "sn65hvd230_g0.h"
|
|
||||||
|
|
||||||
/* Хэндлер FDCAN, сгенерированный CubeMX */
|
|
||||||
extern FDCAN_HandleTypeDef hfdcan1;
|
|
||||||
|
|
||||||
/* Создаем глобальный дескриптор нашего CAN-узла */
|
|
||||||
SN65HVD230_t can_node;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
// ... Автоматическая инициализация HAL, SystemClock, GPIO ...
|
|
||||||
// MX_FDCAN1_Init(); // Инициализация FDCAN из CubeMX
|
|
||||||
|
|
||||||
/* 1. Аппаратный сброс фильтров (Разрешаем прием ВСЕХ пакетов для теста) */
|
|
||||||
FDCAN_FilterTypeDef filter;
|
|
||||||
filter.IdType = FDCAN_STANDARD_ID;
|
|
||||||
filter.FilterIndex = 0;
|
|
||||||
filter.FilterType = FDCAN_FILTER_RANGE;
|
|
||||||
filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
|
||||||
filter.FilterID1 = 0x000;
|
|
||||||
filter.FilterID2 = 0x7FF;
|
|
||||||
HAL_FDCAN_ConfigFilter(&hfdcan1, &filter);
|
|
||||||
|
|
||||||
/* 2. Инициализация структуры трансивера */
|
|
||||||
SN65HVD230_Init(&can_node, &hfdcan1);
|
|
||||||
|
|
||||||
/* 3. Запуск FDCAN шины */
|
|
||||||
SN65HVD230_Start(&can_node);
|
|
||||||
|
|
||||||
/* 4. Подготовка пакета для отправки */
|
|
||||||
CAN_Message_t tx_msg;
|
|
||||||
tx_msg.Identifier = 0x123; // ID сообщения
|
|
||||||
tx_msg.IdType = FDCAN_STANDARD_ID; // Стандартный 11-битный формат
|
|
||||||
tx_msg.TxFrameType = FDCAN_DATA_FRAME; // Кадр данных
|
|
||||||
tx_msg.DataLength = FDCAN_DLC_BYTES_4; // Будем отправлять 4 байта
|
|
||||||
tx_msg.Data[0] = 0xDE;
|
|
||||||
tx_msg.Data[1] = 0xAD;
|
|
||||||
tx_msg.Data[2] = 0xBE;
|
|
||||||
tx_msg.Data[3] = 0xEF;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* Отправляем сообщение раз в секунду с таймаутом ожидания 50 мс */
|
|
||||||
SN65HVD230_Transmit(&can_node, &tx_msg, 50);
|
|
||||||
HAL_Delay(1000);
|
|
||||||
|
|
||||||
/* Неблокирующий опрос входящих сообщений (timeout = 0) */
|
|
||||||
CAN_Message_t rx_msg;
|
|
||||||
if (SN65HVD230_Receive(&can_node, &rx_msg, 0) == HAL_OK) {
|
|
||||||
// Если пришел пакет с ожидаемым ID, обрабатываем буфер rx_msg.Data
|
|
||||||
if (rx_msg.Identifier == 0x500) {
|
|
||||||
// Ваша логика обработки данных здесь...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Используйте код с осторожностью.
|
|
||||||
|
|
||||||
* * *
|
|
||||||
|
|
||||||
### 📝 API Справочник функций
|
|
||||||
|
|
||||||
### `HAL_StatusTypeDef SN65HVD230_Init(SN65HVD230_t *node, FDCAN_HandleTypeDef *hfdcan_handle)`
|
|
||||||
|
|
||||||
Связывает структуру дескриптора со сгенерированным в CubeMX аппаратным хэндлером FDCAN.
|
|
||||||
|
|
||||||
* **Возвращает**: `HAL_OK` при успехе, `HAL_ERROR` если переданы пустые указатели (`NULL`).
|
|
||||||
|
|
||||||
### `HAL_StatusTypeDef SN65HVD230_Start(SN65HVD230_t *node)`
|
|
||||||
|
|
||||||
Включает прерывания по получению новых данных в FIFO 0 и переводит модуль FDCAN из режима инициализации в активный режим работы на шине.
|
|
||||||
|
|
||||||
### `HAL_StatusTypeDef SN65HVD230_Stop(SN65HVD230_t *node)`
|
|
||||||
|
|
||||||
Переводит модуль FDCAN в режим инициализации, безопасно отключая узел от CAN-сети.
|
|
||||||
|
|
||||||
### `HAL_StatusTypeDef SN65HVD230_Transmit(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms)`
|
|
||||||
|
|
||||||
Отправляет классический CAN-кадр в шину. Если TX FIFO заполнено, функция будет ожидать освобождения ячейки в течение времени `timeout_ms`.
|
|
||||||
|
|
||||||
### `HAL_StatusTypeDef SN65HVD230_Receive(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms)`
|
|
||||||
|
|
||||||
Вычитывает входящий CAN-кадр из буфера FIFO 0 периферии. Если буфер пуст, функция ожидает появления сообщения в течение `timeout_ms`.
|
|
||||||
|
|
||||||
* Для неблокирующего опроса шины вызывайте функцию с аргументом `timeout_ms = 0`.
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
#include "sn65hvd230_g0.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Инициализация структуры и привязка к FDCAN в STM32G0
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Init(SN65HVD230_t *node, FDCAN_HandleTypeDef *hfdcan_handle) {
|
|
||||||
if (node == NULL || hfdcan_handle == NULL) {
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->hfdcan = hfdcan_handle;
|
|
||||||
return HAL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Запуск периферийного модуля FDCAN
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Start(SN65HVD230_t *node) {
|
|
||||||
if (node == NULL || node->hfdcan == NULL) return HAL_ERROR;
|
|
||||||
|
|
||||||
// Активируем прерывание по заполнению FIFO 0 (потребуется, если включите IT-режим в CubeMX)
|
|
||||||
HAL_FDCAN_ActivateNotification(node->hfdcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
|
|
||||||
|
|
||||||
return HAL_FDCAN_Start(node->hfdcan);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Остановка модуля FDCAN
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Stop(SN65HVD230_t *node) {
|
|
||||||
if (node == NULL || node->hfdcan == NULL) return HAL_ERROR;
|
|
||||||
return HAL_FDCAN_Stop(node->hfdcan);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Отправка пакета данных в шину (Классический CAN-кадр через FDCAN)
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Transmit(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms) {
|
|
||||||
if (node == NULL || node->hfdcan == NULL || msg == NULL) return HAL_ERROR;
|
|
||||||
|
|
||||||
uint32_t tickstart = HAL_GetTick();
|
|
||||||
FDCAN_TxHeaderTypeDef TxHeader;
|
|
||||||
|
|
||||||
// Конфигурация заголовка кадра в стиле G0 FDCAN
|
|
||||||
TxHeader.Identifier = msg->Identifier;
|
|
||||||
TxHeader.IdType = msg->IdType;
|
|
||||||
TxHeader.TxFrameType = msg->TxFrameType;
|
|
||||||
TxHeader.DataLength = msg->DataLength; // Константы типа FDCAN_DLC_BYTES_8
|
|
||||||
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
|
||||||
TxHeader.BitRateSwitch = FDCAN_BRS_OFF; // Выключаем ускорение данных (для классического CAN)
|
|
||||||
TxHeader.FDFormat = FDCAN_CLASSIC_CAN; // Работаем в режиме совместимости с обычным CAN
|
|
||||||
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
|
|
||||||
TxHeader.MessageMarker = 0;
|
|
||||||
|
|
||||||
// Ожидаем, пока в TX FIFO освободится хотя бы одна ячейка
|
|
||||||
while (HAL_FDCAN_GetTxFifoFreeLevel(node->hfdcan) == 0) {
|
|
||||||
if ((HAL_GetTick() - tickstart) > timeout_ms) {
|
|
||||||
return HAL_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Помещаем сообщение в очередь отправки FDCAN
|
|
||||||
return HAL_FDCAN_AddMessageToTxFifoQ(node->hfdcan, &TxHeader, msg->Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Опрашивающий (блокирующий) прием кадра из FIFO 0
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef SN65HVD230_Receive(SN65HVD230_t *node, CAN_Message_t *msg, uint32_t timeout_ms) {
|
|
||||||
if (node == NULL || node->hfdcan == NULL || msg == NULL) return HAL_ERROR;
|
|
||||||
|
|
||||||
uint32_t tickstart = HAL_GetTick();
|
|
||||||
FDCAN_RxHeaderTypeDef RxHeader;
|
|
||||||
|
|
||||||
// Ожидаем появления нового сообщения в FIFO 0
|
|
||||||
while (HAL_FDCAN_GetRxFifoFillLevel(node->hfdcan, FDCAN_RX_FIFO0) == 0) {
|
|
||||||
if ((HAL_GetTick() - tickstart) > timeout_ms) {
|
|
||||||
return HAL_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Вычитываем данные из FIFO 0
|
|
||||||
if (HAL_FDCAN_GetRxMessage(node->hfdcan, FDCAN_RX_FIFO0, &RxHeader, msg->Data) == HAL_OK) {
|
|
||||||
msg->Identifier = RxHeader.Identifier;
|
|
||||||
msg->IdType = RxHeader.IdType;
|
|
||||||
msg->TxFrameType = RxHeader.RxFrameType;
|
|
||||||
msg->DataLength = RxHeader.DataLength;
|
|
||||||
return HAL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user