2015-04-04 36 views
1

这个问题让我烦恼。我正在做一些基于LPC15XX系列微控制器的定制传感器板的裸机编程。该平台相当于一堆I2C传感器和连接到其中一个UART的蓝牙发射器。这不是LPCxpresso(或类似)电路板之一;它是一个定制设计。将函数分隔成不同文件时的数据损坏

直到今天,所有测试代码都在一个单片文件中,正如所料。随着代码的增长,我决定将主要功能块分解成单独的源文件以简化管理。不幸的是,只要我这样做,该计划开始segfaulting。

正在移动的代码是原始单片文件的副本+粘贴。我已经通过SWD链接使用了GDB。看来我用来命中内部ROM驱动程序的一个静态变量被取消了。稍后解除引用会导致错误。

在静态变量上设置一个监视,我可以看到它的代码行在I2C初始化例程中。有问题的是init是使用恩智浦提供的ROM驱动程序例程完成的。此外,当所有代码都在同一个文件中时,相同的代码没有问题。

问题

  • 什么会核弹那样的文件级静态变量?据我的理解,变量不应该在堆栈上,所以我没有看到导致这种情况的缓冲区溢出。

  • 为什么要移动文件之间的代码暴露此?不应该全部编译并链接到单个命名空间吗?

回复到问题的评论

  • uart_instance定义一次,usart.c和永远只能直接(通过名称)写入一次的呼叫uart_setup的一部分。

  • 同样,i2c_instance定义在main.c(我还没有移动I2C功能)。是静态的并且与uart_instance完全相同。我更新了下面的代码以包含来自两个文件的所有静态变量。

  • 指定的指针实际上在pI2CApi->i2c_set_bitrate(hI2C, BASE_CLOCK, I2C_BAUD);的调用中为空,如通过在所涉及的存储器上设置手表所确定的。

  • 我不能直接跟踪任何ROM驱动程序例程。它们由uC提供,并通过在固定存储器地址处提供的双指针来访问。我检查了这些指针对象(hUartpUartApi),并保留了它们的正确值;只有uart_instance得到破坏。

  • 我创建并转储了此应用程序的地图文件;它不包含对uart_instance(或任何静态变量)的引用。奇怪。我可以根据要求发布完整的内容(有点长)。

代码呕吐

一个字的警告,这个代码是非常典型和未优化。其中绝大多数是从数据表中无耻地复制的。静态变量的

定义(usart.c)静态变量的

static UARTD_API_T* pUartApi;   // USART API function addr table 
static UART_HANDLE_T uart_instance; // Raw storage for USART API 
static UART_HANDLE_T* hUart;   // Handle to USART API 

定义(main.c中)

static I2CD_API_T* pI2CApi;    // I2C API function addr table 
static I2C_HANDLE_T i2c_instance;  // Raw storage for I2C API 
static I2C_HANDLE_T* hI2C;    // Handle to I2C API 

初始化静态手柄(usart.c)

int setupUSART0(int sys_clock, int baud) { 

    UART_CONFIG_T config; 
    uint32_t frg_val = 0; 
    uint32_t size_in_bytes; 

    // Enable USART0 clock 
    LPC_SYSCON->SYSAHBCLKCTRL1 |= ((1UL << 17)); 

    // Configure USART clock divider 
    LPC_SYSCON->UARTCLKDIV = (uint8_t)USART_PERIPH_PRESCALE; 

    // Configure USART0 pins 
    LPC_SWM->PINASSIGN0 = 0; 
    LPC_SWM->PINASSIGN0 |= ((uint8_t)18) << 0;  // PIO0_18, tx 
    LPC_SWM->PINASSIGN0 |= ((uint8_t)13) << 8;  // PIO0_13, rx 
    LPC_SWM->PINASSIGN0 |= ((uint8_t)0xFF) << 16; // Not wired, rts 
    LPC_SWM->PINASSIGN0 |= ((uint8_t)0xFF) << 24; // Not wired, cts 

    // Get handle to USART API 
    pUartApi = getUartDriver(); 

    // Initialize memory for UART API 
    size_in_bytes = pUartApi->uart_get_mem_size(); 
    if (10 < (size_in_bytes/4)) return -1; 
    hUart = pUartApi->uart_setup(LPC_USART0_BASE, (uint8_t*)&uart_instance); // <- uart_instance initialized here 

    // Initialize USART API 
    config.sys_clk_in_hz = sys_clock/USART_PERIPH_PRESCALE; 
    config.baudrate_in_hz = baud; 
    config.config = 1;    // 8N1 
    config.sync_mod = 0; 
    config.error_en = 0; 
    frg_val = (pUartApi->uart_init(hUart, &config) << 8) | 0xFF; 

    // Configure USART fractional divider 
    if (!frg_val) return -1; 
    LPC_SYSCON->FRGCTRL  = frg_val; 

    // Enable USART0 in NVIC 
    NVIC->ISER0 |= ((1UL << 21)); 

    // Enable UART0 interrupts 
    LPC_USART0->INTENSET |= ((1UL << 0)); 

    return 0; 
} 

断开指针的I2C初始化代码(main.c)

ErrorCode_t setupI2C() { 

    ErrorCode_t err; 

    // Enable I2C clock 

    LPC_SYSCON->SYSAHBCLKCTRL1 |= ((1UL << 13)); 
    LPC_I2C0->DIV = 0x0078; // 120 decimal 

    LPC_I2C0->MSTTIME = 0x00; // SCL high/low = 2 clocks each 

    //DEBUG 
    LPC_SWM->PINENABLE1 = 0x00; 

    // Enable interrupts 
    NVIC->ISER0 |= ((1UL << 24));    // ISE_I2C0 
    LPC_I2C0->INTENSET |= ((1UL << 0));   // MSTPENDINGEN 
    LPC_I2C0->INTENSET |= ((1UL << 8));   // SLVPENDINGEN 

    // Get handle to I2C API 
    pI2CApi = getI2CDriver(); 

    // Initialize memory for UART API 
    hI2C = pI2CApi->i2c_setup(LPC_I2C0_BASE, (uint32_t*)&i2c_instance); 

    // This NULLS uart_instance somehow 
    // Set bitrate 
    err = pI2CApi->i2c_set_bitrate(hI2C, BASE_CLOCK, I2C_BAUD); 

    // Set master mode 
    LPC_I2C0->CFG = ((1UL << 0));    // MSTEN 

    return err; 
} 
+1

你可以转储'i2c_set_bitrate'的程序集吗? 'i2c_setup'中可能有些东西可以让你启动segfault? 'i2c_instance'是静态的吗?你是否在'extern'声明的其他文件中使用'uart_instance'?我做的另一件事是看链接器映射文件 - 请参阅附近的变量.. – Abhi 2015-04-04 01:35:01

+0

除了@Abhi写了什么之外,setupI2C()的哪一行会消失?我认为这可能是对i2c_setup()的调用。设置变量i2c_instance。如果这个变量声明不正确,它可能会覆盖会影响uart_instance的相邻全局内存。 – 2015-04-04 12:23:14

+0

如果链接器不吐出静态变量 - 删除静态声明。由于您在其他地方的评论表明没有其他'uart_instance'。 – Abhi 2015-04-05 06:28:10

回答

1

我没有看到上面的代码错误。

通常,可以通过将代码拆分成几个文件而意外引入的错误是静态变量的重复。例如,在main.c和usart.c中都可能有一个static UART_HANDLE_T uart_instance;(或者甚至在两个包含的某些.h中都是奇怪的)。一切都会编译并链接OK,但main.c和usart.c中的函数将使用不相关的变量,并且程序逻辑将随着数据损坏的可能性而改变。

现在,这是一个与您的代码没有直接关系的通用注释。有一些机会可以帮助你...祝你好运狩猎臭虫!

+0

我只是通过我的每个静态变量的代码grepped加倍确定;每个只定义一次。不过我注意到'uart_instance'变量占用了一个很好的循环地址0x40004000。这非常接近用户记忆的开始,所以我不确定这是否是一个问题。 – phobos51594 2015-04-04 01:41:41

+1

作为测试,尝试声明一个64字节或128字节的缓冲区,或者在uart_instance之上的任何合理的 - 你的用户内存之前可能会损坏任何内存区域。 – Abhi 2015-04-05 06:30:45

+0

对不起,在响应延迟;其中一个电压调节器出现故障并煮熟板,所以另一个必须制作。无论如何,你击中了头部。显然,数据表中提供的数据结构与从API例程返回的结构大小不匹配。 API需要额外的8个字节,这就是为什么我的句柄(直接定义在后面)被破坏的原因。非常相信API!我唯一的问题仍然是为什么直到我拆分源文件时,这个问题才显示出来?它不应该一直发生吗?这是由于对齐或类似? – phobos51594 2015-04-24 17:33:31