STM32F100 模拟 STM8 SWIM 接口实现

基于STM32F100模拟STM8 SWIM接口的方案


一、SWIM接口原理

1、SWIM物理层特性

  • 单线双向:数据+电源(可选)
  • 开漏输出:需要外部上拉电阻(4.7kΩ-10kΩ)
  • 通信速率:低速8kHz,高速800kHz
  • 协议:曼彻斯特编码

2、引脚连接

STM32F100              STM8 SWIM
PA0 (SWIM) -----/\/\---- NRST (SWIM)
                4.7kΩ
                  ↓
                3.3V

必须加上拉电阻,否则通信不稳定


二、硬件配置

1、STM32F100最小系统

  • 主频:24MHz
  • 供电:3.3V
  • 调试:SWD接口

2、外部电路

电源管理:
3.3V → LDO → STM8 VDD
         ↓
     目标板供电

三、SWIM协议实现

1、头文件定义

// swim.h
#ifndef __SWIM_H
#define __SWIM_H

#include "stm32f1xx_hal.h"

// SWIM状态
typedef enum {
    SWIM_IDLE = 0,
    SWIM_ACTIVE,
    SWIM_SYNC,
    SWIM_COMMAND,
    SWIM_DATA,
    SWIM_ERROR
} SWIM_State_t;

// SWIM命令
typedef enum {
    SWIM_CMD_ROFF = 0x00,     // 读选项字节
    SWIM_CMD_WOPT  = 0x01,    // 写选项字节
    SWIM_CMD_RSTAT = 0x02,    // 读状态
    SWIM_CMD_WCFG  = 0x03,    // 写配置
    SWIM_CMD_RMEM  = 0x80,    // 读内存
    SWIM_CMD_WMEM  = 0x81,    // 写内存
    SWIM_CMD_SRST  = 0xFF     // 软件复位
} SWIM_Command_t;

// SWIM错误码
typedef enum {
    SWIM_OK = 0,
    SWIM_TIMEOUT,
    SWIM_CRC_ERROR,
    SWIM_NO_RESPONSE,
    SWIM_BUS_ERROR
} SWIM_Error_t;

// SWIM句柄
typedef struct {
    GPIO_TypeDef* port;
    uint16_t pin;
    
    SWIM_State_t state;
    uint8_t target_id;
    uint32_t timeout;
    
    // 定时器用于精确延时
    TIM_HandleTypeDef* htim;
    
    // 统计
    uint32_t tx_count;
    uint32_t rx_count;
    uint32_t error_count;
} SWIM_Handle_t;

// 函数声明
void SWIM_Init(SWIM_Handle_t* hswim, GPIO_TypeDef* port, uint16_t pin, TIM_HandleTypeDef* htim);
SWIM_Error_t SWIM_Activate(SWIM_Handle_t* hswim);
SWIM_Error_t SWIM_Reset(SWIM_Handle_t* hswim);
SWIM_Error_t SWIM_Read_Byte(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* data);
SWIM_Error_t SWIM_Write_Byte(SWIM_Handle_t* hswim, uint32_t addr, uint8_t data);
SWIM_Error_t SWIM_Read_Memory(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* buffer, uint16_t size);
SWIM_Error_t SWIM_Write_Memory(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* data, uint16_t size);
SWIM_Error_t SWIM_Erase_Page(SWIM_Handle_t* hswim, uint32_t addr);
void SWIM_Set_Speed(SWIM_Handle_t* hswim, uint32_t speed_hz);
uint8_t SWIM_Calculate_CRC(uint8_t* data, uint8_t len);

// 调试函数
void SWIM_Print_Status(SWIM_Handle_t* hswim);

#endif

2、SWIM初始化

// swim.c
#include "swim.h"
#include <string.h>

// 全局句柄
static SWIM_Handle_t* swim_handle = NULL;

// 精确延时函数(基于定时器)
static void SWIM_Delay_us(uint32_t us)
{
    __HAL_TIM_SET_COUNTER(swim_handle->htim, 0);
    HAL_TIM_Base_Start(swim_handle->htim);
    
    while (__HAL_TIM_GET_COUNTER(swim_handle->htim) < us);
    
    HAL_TIM_Base_Stop(swim_handle->htim);
}

// 初始化SWIM接口
void SWIM_Init(SWIM_Handle_t* hswim, GPIO_TypeDef* port, uint16_t pin, TIM_HandleTypeDef* htim)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    swim_handle = hswim;
    
    // 保存参数
    hswim->port = port;
    hswim->pin = pin;
    hswim->htim = htim;
    hswim->state = SWIM_IDLE;
    hswim->timeout = 1000;  // 默认1ms超时
    
    // 初始化GPIO为开漏输出
    GPIO_InitStruct.Pin = pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;  // 开漏输出
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(port, &GPIO_InitStruct);
    
    // 默认释放总线(高电平)
    HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);
    
    // 初始化定时器
    if (htim != NULL) {
        HAL_TIM_Base_Start(htim);
    }
}

3、SWIM激活序列(关键)

// SWIM激活序列
SWIM_Error_t SWIM_Activate(SWIM_Handle_t* hswim)
{
    uint32_t start_time = HAL_GetTick();
    
    // 1. 发送16us低电平
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_RESET);
    SWIM_Delay_us(16);
    
    // 2. 发送>1ms的高电平
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_SET);
    SWIM_Delay_us(1500);  // 1.5ms
    
    // 3. 发送8us低电平
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_RESET);
    SWIM_Delay_us(8);
    
    // 4. 释放总线,等待响应
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_SET);
    
    // 切换为输入模式检测响应
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = hswim->pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
    
    // 5. 等待STM8响应(60us内拉低至少2us)
    uint8_t response_received = 0;
    for (int i = 0; i < 60; i++) {  // 检查60us
        if (HAL_GPIO_ReadPin(hswim->port, hswim->pin) == GPIO_PIN_RESET) {
            response_received = 1;
            break;
        }
        SWIM_Delay_us(1);
    }
    
    if (!response_received) {
        // 切换回输出模式
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
        return SWIM_NO_RESPONSE;
    }
    
    // 6. 等待响应结束
    while (HAL_GPIO_ReadPin(hswim->port, hswim->pin) == GPIO_PIN_RESET) {
        if (HAL_GetTick() - start_time > hswim->timeout) {
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
            return SWIM_TIMEOUT;
        }
    }
    
    // 7. 发送同步字节 0x7F
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
    
    SWIM_Send_Byte(hswim, 0x7F);
    
    // 8. 接收同步响应
    uint8_t sync_response = 0;
    SWIM_Error_t err = SWIM_Receive_Byte(hswim, &sync_response);
    
    if (err != SWIM_OK) {
        return err;
    }
    
    if (sync_response != 0x7F) {
        return SWIM_ERROR;
    }
    
    hswim->state = SWIM_ACTIVE;
    return SWIM_OK;
}

// 复位STM8
SWIM_Error_t SWIM_Reset(SWIM_Handle_t* hswim)
{
    // 发送复位序列
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_RESET);
    SWIM_Delay_us(16);
    
    HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_SET);
    SWIM_Delay_us(1000);  // 1ms
    
    hswim->state = SWIM_IDLE;
    return SWIM_OK;
}

4、位传输函数

// 发送一个位
static void SWIM_Send_Bit(SWIM_Handle_t* hswim, uint8_t bit)
{
    if (bit) {
        // 发送'1': 低电平1us,高电平3us
        HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_RESET);
        SWIM_Delay_us(1);
        HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_SET);
        SWIM_Delay_us(3);
    } else {
        // 发送'0': 低电平3us,高电平1us
        HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_RESET);
        SWIM_Delay_us(3);
        HAL_GPIO_WritePin(hswim->port, hswim->pin, GPIO_PIN_SET);
        SWIM_Delay_us(1);
    }
}

// 接收一个位
static uint8_t SWIM_Receive_Bit(SWIM_Handle_t* hswim)
{
    uint32_t start_time = HAL_GetTick();
    uint8_t bit = 0;
    
    // 切换为输入模式
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = hswim->pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
    
    // 等待下降沿
    while (HAL_GPIO_ReadPin(hswim->port, hswim->pin) == GPIO_PIN_SET) {
        if (HAL_GetTick() - start_time > hswim->timeout) {
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
            return 0xFF;  // 超时
        }
    }
    
    // 测量低电平时间
    uint32_t low_start = micros();
    while (HAL_GPIO_ReadPin(hswim->port, hswim->pin) == GPIO_PIN_RESET) {
        if (HAL_GetTick() - start_time > hswim->timeout) {
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
            HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
            return 0xFF;
        }
    }
    uint32_t low_duration = micros() - low_start;
    
    // 判断是0还是1
    if (low_duration > 2) {  // 低电平>2us是0
        bit = 0;
    } else {
        bit = 1;
    }
    
    // 切换回输出模式
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    HAL_GPIO_Init(hswim->port, &GPIO_InitStruct);
    
    return bit;
}

5、字节传输函数

// 发送一个字节
static SWIM_Error_t SWIM_Send_Byte(SWIM_Handle_t* hswim, uint8_t data)
{
    // 发送起始位(0)
    SWIM_Send_Bit(hswim, 0);
    
    // 发送8个数据位(LSB first)
    for (int i = 0; i < 8; i++) {
        SWIM_Send_Bit(hswim, (data >> i) & 0x01);
    }
    
    // 计算并发送奇偶校验位
    uint8_t parity = 0;
    for (int i = 0; i < 8; i++) {
        if (data & (1 << i)) parity ^= 1;
    }
    SWIM_Send_Bit(hswim, parity);
    
    // 发送停止位(1)
    SWIM_Send_Bit(hswim, 1);
    
    hswim->tx_count++;
    return SWIM_OK;
}

// 接收一个字节
static SWIM_Error_t SWIM_Receive_Byte(SWIM_Handle_t* hswim, uint8_t* data)
{
    uint8_t byte = 0;
    uint8_t bit;
    
    // 接收起始位
    bit = SWIM_Receive_Bit(hswim);
    if (bit == 0xFF) return SWIM_TIMEOUT;
    if (bit != 0) return SWIM_ERROR;  // 起始位应该是0
    
    // 接收8个数据位
    for (int i = 0; i < 8; i++) {
        bit = SWIM_Receive_Bit(hswim);
        if (bit == 0xFF) return SWIM_TIMEOUT;
        byte |= (bit << i);
    }
    
    // 接收奇偶校验位
    uint8_t received_parity = SWIM_Receive_Bit(hswim);
    if (received_parity == 0xFF) return SWIM_TIMEOUT;
    
    // 计算奇偶校验
    uint8_t calculated_parity = 0;
    for (int i = 0; i < 8; i++) {
        if (byte & (1 << i)) calculated_parity ^= 1;
    }
    
    if (received_parity != calculated_parity) {
        return SWIM_CRC_ERROR;
    }
    
    // 接收停止位
    bit = SWIM_Receive_Bit(hswim);
    if (bit == 0xFF) return SWIM_TIMEOUT;
    if (bit != 1) return SWIM_ERROR;  // 停止位应该是1
    
    *data = byte;
    hswim->rx_count++;
    return SWIM_OK;
}

6、内存读写函数

// 读取一个字节
SWIM_Error_t SWIM_Read_Byte(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* data)
{
    SWIM_Error_t err;
    uint8_t cmd_buffer[5];
    
    if (hswim->state != SWIM_ACTIVE) {
        return SWIM_ERROR;
    }
    
    // 构建读命令
    cmd_buffer[0] = SWIM_CMD_RMEM;  // 读内存命令
    cmd_buffer[1] = (addr >> 16) & 0xFF;  // 地址高位
    cmd_buffer[2] = (addr >> 8) & 0xFF;
    cmd_buffer[3] = addr & 0xFF;         // 地址低位
    cmd_buffer[4] = SWIM_Calculate_CRC(cmd_buffer, 4);  // CRC
    
    // 发送命令
    for (int i = 0; i < 5; i++) {
        err = SWIM_Send_Byte(hswim, cmd_buffer[i]);
        if (err != SWIM_OK) return err;
    }
    
    // 接收数据
    err = SWIM_Receive_Byte(hswim, data);
    if (err != SWIM_OK) return err;
    
    return SWIM_OK;
}

// 写入一个字节
SWIM_Error_t SWIM_Write_Byte(SWIM_Handle_t* hswim, uint32_t addr, uint8_t data)
{
    SWIM_Error_t err;
    uint8_t cmd_buffer[6];
    
    if (hswim->state != SWIM_ACTIVE) {
        return SWIM_ERROR;
    }
    
    // 构建写命令
    cmd_buffer[0] = SWIM_CMD_WMEM;  // 写内存命令
    cmd_buffer[1] = (addr >> 16) & 0xFF;  // 地址高位
    cmd_buffer[2] = (addr >> 8) & 0xFF;
    cmd_buffer[3] = addr & 0xFF;         // 地址低位
    cmd_buffer[4] = data;                // 数据
    cmd_buffer[5] = SWIM_Calculate_CRC(cmd_buffer, 5);  // CRC
    
    // 发送命令
    for (int i = 0; i < 6; i++) {
        err = SWIM_Send_Byte(hswim, cmd_buffer[i]);
        if (err != SWIM_OK) return err;
    }
    
    // 接收响应
    uint8_t response = 0;
    err = SWIM_Receive_Byte(hswim, &response);
    if (err != SWIM_OK) return err;
    
    if (response != 0x00) {  // 0x00表示写入成功
        return SWIM_ERROR;
    }
    
    return SWIM_OK;
}

// 批量读取内存
SWIM_Error_t SWIM_Read_Memory(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* buffer, uint16_t size)
{
    SWIM_Error_t err;
    
    for (uint16_t i = 0; i < size; i++) {
        err = SWIM_Read_Byte(hswim, addr + i, &buffer[i]);
        if (err != SWIM_OK) {
            return err;
        }
        
        // 小延时,防止目标设备忙
        SWIM_Delay_us(10);
    }
    
    return SWIM_OK;
}

// 批量写入内存
SWIM_Error_t SWIM_Write_Memory(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* data, uint16_t size)
{
    SWIM_Error_t err;
    
    for (uint16_t i = 0; i < size; i++) {
        err = SWIM_Write_Byte(hswim, addr + i, data[i]);
        if (err != SWIM_OK) {
            return err;
        }
        
        // 小延时
        SWIM_Delay_us(10);
    }
    
    return SWIM_OK;
}

7、Flash编程函数

// 擦除一页
SWIM_Error_t SWIM_Erase_Page(SWIM_Handle_t* hswim, uint32_t addr)
{
    SWIM_Error_t err;
    uint8_t cmd_buffer[5];
    
    // 构建擦除命令
    cmd_buffer[0] = 0x82;  // 页擦除命令
    cmd_buffer[1] = (addr >> 16) & 0xFF;
    cmd_buffer[2] = (addr >> 8) & 0xFF;
    cmd_buffer[3] = addr & 0xFF;
    cmd_buffer[4] = SWIM_Calculate_CRC(cmd_buffer, 4);
    
    // 发送命令
    for (int i = 0; i < 5; i++) {
        err = SWIM_Send_Byte(hswim, cmd_buffer[i]);
        if (err != SWIM_OK) return err;
    }
    
    // 接收响应
    uint8_t response = 0;
    err = SWIM_Receive_Byte(hswim, &response);
    if (err != SWIM_OK) return err;
    
    if (response != 0x00) {
        return SWIM_ERROR;
    }
    
    // 等待擦除完成
    uint32_t start_time = HAL_GetTick();
    while (HAL_GetTick() - start_time < 100) {  // 等待100ms
        uint8_t status = 0;
        SWIM_Read_Status(hswim, &status);
        
        if ((status & 0x01) == 0) {  // BUSY位为0表示完成
            break;
        }
        
        HAL_Delay(1);
    }
    
    return SWIM_OK;
}

// 读取状态寄存器
SWIM_Error_t SWIM_Read_Status(SWIM_Handle_t* hswim, uint8_t* status)
{
    uint8_t cmd_buffer[2];
    SWIM_Error_t err;
    
    cmd_buffer[0] = SWIM_CMD_RSTAT;
    cmd_buffer[1] = SWIM_Calculate_CRC(cmd_buffer, 1);
    
    for (int i = 0; i < 2; i++) {
        err = SWIM_Send_Byte(hswim, cmd_buffer[i]);
        if (err != SWIM_OK) return err;
    }
    
    err = SWIM_Receive_Byte(hswim, status);
    return err;
}

8、CRC计算

// 计算CRC
uint8_t SWIM_Calculate_CRC(uint8_t* data, uint8_t len)
{
    uint8_t crc = 0;
    
    for (uint8_t i = 0; i < len; i++) {
        crc ^= data[i];
    }
    
    return crc;
}

9、STM8 Flash编程器

// stm8_programmer.c
#include "swim.h"

// STM8 Flash参数
typedef struct {
    uint32_t flash_start;     // Flash起始地址
    uint32_t flash_size;      // Flash大小
    uint16_t page_size;       // 页大小
    uint8_t  family;          // 芯片系列
} STM8_FlashInfo_t;

// STM8芯片列表
static const STM8_FlashInfo_t stm8_chips[] = {
    // STM8S003/103
    {0x8000, 8192, 128, 0},
    // STM8S005/105
    {0x8000, 32768, 128, 0},
    // STM8S207/208
    {0x8000, 128*1024, 1024, 1},
    // STM8L101
    {0x8000, 8192, 128, 2},
    // STM8L151/152
    {0x8000, 32768, 256, 2},
};

// 读取STM8 ID
SWIM_Error_t STM8_Read_ID(SWIM_Handle_t* hswim, uint16_t* chip_id)
{
    SWIM_Error_t err;
    uint8_t id_low, id_high;
    
    // 读取低字节
    err = SWIM_Read_Byte(hswim, 0x48CD, &id_low);
    if (err != SWIM_OK) return err;
    
    // 读取高字节
    err = SWIM_Read_Byte(hswim, 0x48CE, &id_high);
    if (err != SWIM_OK) return err;
    
    *chip_id = (id_high << 8) | id_low;
    return SWIM_OK;
}

// 擦除整个Flash
SWIM_Error_t STM8_Mass_Erase(SWIM_Handle_t* hswim)
{
    SWIM_Error_t err;
    uint8_t cmd_buffer[2];
    
    printf("开始全片擦除...\n");
    
    cmd_buffer[0] = 0x84;  // 全片擦除命令
    cmd_buffer[1] = SWIM_Calculate_CRC(cmd_buffer, 1);
    
    for (int i = 0; i < 2; i++) {
        err = SWIM_Send_Byte(hswim, cmd_buffer[i]);
        if (err != SWIM_OK) return err;
    }
    
    // 接收响应
    uint8_t response = 0;
    err = SWIM_Receive_Byte(hswim, &response);
    if (err != SWIM_OK) return err;
    
    if (response != 0x00) {
        return SWIM_ERROR;
    }
    
    // 等待擦除完成
    printf("擦除中,请等待...\n");
    HAL_Delay(1000);  // STM8全片擦除需要较长时间
    
    printf("全片擦除完成\n");
    return SWIM_OK;
}

// 编程Flash
SWIM_Error_t STM8_Program_Flash(SWIM_Handle_t* hswim, uint32_t addr, uint8_t* data, uint32_t size)
{
    SWIM_Error_t err;
    uint16_t chip_id;
    const STM8_FlashInfo_t* chip_info = NULL;
    
    // 1. 读取芯片ID
    err = STM8_Read_ID(hswim, &chip_id);
    if (err != SWIM_OK) {
        printf("读取芯片ID失败\n");
        return err;
    }
    
    printf("芯片ID: 0x%04X\n", chip_id);
    
    // 2. 根据ID获取芯片信息
    switch (chip_id) {
        case 0x004A:  // STM8S003/103
            chip_info = &stm8_chips[0];
            printf("检测到: STM8S003/103 (8KB Flash)\n");
            break;
        case 0x004B:  // STM8S005/105
            chip_info = &stm8_chips[1];
            printf("检测到: STM8S005/105 (32KB Flash)\n");
            break;
        default:
            printf("未知芯片,使用默认参数\n");
            chip_info = &stm8_chips[0];
    }
    
    // 3. 检查地址范围
    if (addr < chip_info->flash_start || 
        addr + size > chip_info->flash_start + chip_info->flash_size) {
        printf("地址超出范围\n");
        return SWIM_ERROR;
    }
    
    // 4. 按页编程
    uint32_t current_addr = addr;
    uint32_t bytes_remaining = size;
    uint8_t* current_data = data;
    
    while (bytes_remaining > 0) {
        // 计算当前页
        uint32_t page_start = (current_addr / chip_info->page_size) * chip_info->page_size;
        uint32_t page_offset = current_addr - page_start;
        uint32_t bytes_in_page = chip_info->page_size - page_offset;
        
        if (bytes_in_page > bytes_remaining) {
            bytes_in_page = bytes_remaining;
        }
        
        printf("编程页面: 0x%06lX, 大小: %lu字节\n", page_start, bytes_in_page);
        
        // 擦除页面
        err = SWIM_Erase_Page(hswim, page_start);
        if (err != SWIM_OK) {
            printf("页面擦除失败\n");
            return err;
        }
        
        // 写入页面数据
        for (uint32_t i = 0; i < bytes_in_page; i++) {
            err = SWIM_Write_Byte(hswim, current_addr + i, current_data[i]);
            if (err != SWIM_OK) {
                printf("写入失败在地址: 0x%06lX\n", current_addr + i);
                return err;
            }
            
            // 验证写入
            uint8_t verify_data = 0;
            SWIM_Read_Byte(hswim, current_addr + i, &verify_data);
            if (verify_data != current_data[i]) {
                printf("验证失败在地址: 0x%06lX (写入: 0x%02X, 读取: 0x%02X)\n", 
                       current_addr + i, current_data[i], verify_data);
                return SWIM_ERROR;
            }
        }
        
        // 更新指针
        current_addr += bytes_in_page;
        current_data += bytes_in_page;
        bytes_remaining -= bytes_in_page;
        
        printf("进度: %.1f%%\n", 100.0f * (size - bytes_remaining) / size);
    }
    
    printf("编程完成\n");
    return SWIM_OK;
}

四、主程序示例

// main.c
#include "main.h"
#include "swim.h"
#include "stm8_programmer.h"

// SWIM句柄
SWIM_Handle_t hswim;
TIM_HandleTypeDef htim2;

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    // 初始化外设
    MX_GPIO_Init();
    MX_TIM2_Init();  // 用于精确延时
    
    // 初始化SWIM
    SWIM_Init(&hswim, GPIOA, GPIO_PIN_0, &htim2);
    
    printf("STM8 SWIM编程器 v1.0\n");
    printf("====================\n");
    
    // 激活STM8
    printf("尝试激活STM8...\n");
    SWIM_Error_t err = SWIM_Activate(&hswim);
    
    if (err != SWIM_OK) {
        printf("激活失败: %d\n", err);
        return 1;
    }
    
    printf("STM8激活成功\n");
    
    // 读取芯片ID
    uint16_t chip_id = 0;
    err = STM8_Read_ID(&hswim, &chip_id);
    if (err == SWIM_OK) {
        printf("芯片ID: 0x%04X\n", chip_id);
    }
    
    // 示例:读取Flash内容
    uint8_t flash_data[256];
    printf("读取前256字节Flash...\n");
    
    err = SWIM_Read_Memory(&hswim, 0x8000, flash_data, 256);
    if (err == SWIM_OK) {
        printf("读取成功\n");
        
        // 显示前16字节
        printf("地址  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
        printf("8000 ");
        for (int i = 0; i < 16; i++) {
            printf("%02X ", flash_data[i]);
        }
        printf("\n");
    }
    
    // 示例:编程Flash
    uint8_t program_data[] = {
        0x82, 0x00, 0x00, 0x20, 0x4E, 0x71, 0xAE, 0x02,
        0x4E, 0x75, 0x20, 0x4E, 0x71, 0xAE, 0x02, 0x4E
    };
    
    printf("开始编程Flash...\n");
    err = STM8_Program_Flash(&hswim, 0x8000, program_data, sizeof(program_data));
    if (err == SWIM_OK) {
        printf("编程成功\n");
    } else {
        printf("编程失败: %d\n", err);
    }
    
    // 重置STM8
    SWIM_Reset(&hswim);
    
    // 显示统计信息
    SWIM_Print_Status(&hswim);
    
    while (1) {
        HAL_Delay(1000);
    }
}

五、CubeMX配置

1、GPIO配置

  • PA0: Output Open Drain, No pull, High speed

2、定时器配置(TIM2)

  • Prescaler: 23 (24MHz/24 = 1MHz)
  • Counter Period: 65535
  • Clock Division: 0
  • Auto-reload: Enable

参考代码 STM8 SWIM接口,使用STM32F100单片机实现 www.youwenfan.com/contentcnu/70103.html

六、调试技巧

1、逻辑分析仪调试

// 添加调试引脚
#define DEBUG_PIN_SET()   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)
#define DEBUG_PIN_CLR()   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)

// 在关键位置添加
DEBUG_PIN_SET();
SWIM_Send_Byte(&hswim, data);
DEBUG_PIN_CLR();

2、错误诊断

void SWIM_Print_Status(SWIM_Handle_t* hswim)
{
    printf("=== SWIM状态 ===\n");
    printf("发送字节数: %lu\n", hswim->tx_count);
    printf("接收字节数: %lu\n", hswim->rx_count);
    printf("错误计数: %lu\n", hswim->error_count);
    printf("当前状态: %d\n", hswim->state);
}

七、性能优化

1. 使用DMA+定时器

// 使用定时器产生精确的PWM波形
void SWIM_Send_Byte_DMA(uint8_t data)
{
    // 将字节转换为PWM波形
    uint8_t waveform[40];  // 每个位4个采样点
    
    // 配置DMA传输
    HAL_TIM_PWM_Start_DMA(&htim, TIM_CHANNEL_1, waveform, 40);
}

2. 中断驱动接收

// 使用外部中断检测下降沿
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == SWIM_PIN) {
        // 记录下降沿时间
        uint32_t edge_time = micros();
        
        // 计算位值
        if (edge_time - last_edge_time > 2) {
            received_bit = 0;  // 长低电平是0
        } else {
            received_bit = 1;  // 短低电平是1
        }
        
        last_edge_time = edge_time;
    }
}

八、生产测试

// production_test.c
void SWIM_Production_Test(void)
{
    printf("=== SWIM生产测试 ===\n");
    
    // 1. 测试激活
    printf("1. 测试激活...");
    if (SWIM_Activate(&hswim) == SWIM_OK) {
        printf("通过\n");
    } else {
        printf("失败\n");
        return;
    }
    
    // 2. 测试ID读取
    printf("2. 测试ID读取...");
    uint16_t chip_id = 0;
    if (STM8_Read_ID(&hswim, &chip_id) == SWIM_OK) {
        printf("通过 (ID: 0x%04X)\n", chip_id);
    } else {
        printf("失败\n");
    }
    
    // 3. 测试读写
    printf("3. 测试读写...");
    uint8_t test_data[8] = {0xAA, 0x55, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
    uint8_t read_data[8];
    
    // 写入测试RAM区域
    if (SWIM_Write_Memory(&hswim, 0x0000, test_data, 8) == SWIM_OK &&
        SWIM_Read_Memory(&hswim, 0x0000, read_data, 8) == SWIM_OK &&
        memcmp(test_data, read_data, 8) == 0) {
        printf("通过\n");
    } else {
        printf("失败\n");
    }
    
    printf("=== 测试完成 ===\n");
}
posted @ 2026-05-17 11:49  yes_go  阅读(11)  评论(0)    收藏  举报