我正在使用ATxmega128A1 8位微控制器,我正在试图弄清楚为什么我的内存缓冲区表现得很奇怪。
我有一个以下结构的FIFO缓冲区:
typedef struct
{
FIFOid ID; //ID value to determine the type of FIFO being used
BOOL LOCK; //A lock to prevent multiple FIFO accessing (i.e. data corruption)
UINT16 Start, End; //Value of the current start and end FIFO index
UINT16 volatile NbBytes; //Number of bytes currently inside the FIFO
UINT8 Buffer[FIFO_SIZE]; //Memory buffer for the FIFO buffer
} TFIFO;
我定义了2个FIFO:
//FIFO Buffers for USART
TFIFO RxFIFO; //Creates the Receive FIFO
TFIFO TxFIFO; //Creates the Transmit FIFO
FIFO_SIZE在哪里
#define FIFO_SIZE 256
当我想从Buffer []获取一个字节时,我通过这个函数传递一个指向FIFO的指针:
BOOL FIFO_Get(TFIFO * const FIFO, UINT8 * const dataPtr);
这样可以正常工作,但是,一旦我将FIFO_SIZE增加到~510字节以上 - 将此FIFO指针传递给此函数会导致另一个我的一个FIFO'缓冲区有待改变。
我在调试器上看到,这一行没有问题:
if(FIFO_Get(&TxFIFO, &data)){ //Get a byte from TxFIFO
一旦我跳过,并且它被传递给函数,RxFIFO-> Buffer []数组被修改,即更大的地址值。 FIFO_Get函数:
// ----------------------------------------
// FIFO_Get
// ----------------------------------------
// Remove one character from the FIFO
// Input:
// FIFO is a pointer to a FIFO struct with data to be retrieved
// dataPtr is a pointer to a memory location to place the retrieved byte
// Output:
// TRUE if the operation was successful and the data is valid
// Conditions:
// Assumes that FIFO_Init has been called
BOOL FIFO_Get(TFIFO * const FIFO, UINT8 * const dataPtr)
{
BOOL FIFOGetSuccess;
FIFOGetSuccess = bFALSE;
//disable interrupts
//if we're GETTING from the USART receive FIFO
//we need to disable the receive interrupt so
//there is no data being 'Put' during a 'Get'
if(FIFO->ID == URX){
USARTD0.CTRLA = USART_RXCINTLVL_OFF_gc; //Rx interrupts off
USARTD1.CTRLA = USART_RXCINTLVL_OFF_gc; //Rx interrupts off
}
//Attempt to get a byte from the FIFO
if(FIFO->LOCK == bFALSE){ //Check that the FIFO is not locked
FIFO->LOCK = bTRUE; //lock the FIFO
if (FIFO->NbBytes == 0){ //Checks whether FIFO is empty; number of bytes in FIFO = 0
FIFOGetSuccess = bFALSE; //If empty, false is Returned
}else{
*dataPtr = FIFO->Buffer[FIFO->Start]; //Reads the byte in the FIFO start position, and saves it to the location of the data pointer
if (FIFO->Start == (FIFO_SIZE - 1)){ //Checks whether the start position is equal to FIFO size, the last valid 8 bit number
FIFO->Start = 0; //If so, the position is set to 0
}else{ //If not fifo size;
FIFO->Start++; //Increments the start position by 1
}
FIFO->NbBytes--; //Decrements the number of bytes in the FIFO by 1
FIFOGetSuccess = bTRUE; //Returns true if this is successful
}
FIFO->LOCK = bFALSE; //unlock the FIFO
}
//re-enable interrupts
if(FIFO->ID == URX){
USARTD0.CTRLA = USART_RXCINTLVL_LO_gc; //low level interrupts on Rx
USARTD1.CTRLA = USART_RXCINTLVL_LO_gc; //low level interrupts on Rx
}
return FIFOGetSuccess;
}
我的猜测是我不能在微控制器中安全地分配内存,但是在构建之后芯片中似乎还有足够的内存:
Program Memory Usage : 21460 bytes 15.4 % Full
Data Memory Usage : 6967 bytes 12.1 % Full
我如何解决这个问题?我做错了什么?
编辑:
我发现增加FIFO SIZE会将FIFO缓冲区映射到SRAM地址范围内(ATxmega128A1的SRAM从0x2000变为0x3FFF)
当另一个FIFO通过函数
时,地址0x3FF7到0x3FFF正在改变编辑2: Elf Files
答案 0 :(得分:1)
从ELF文件中,我可以看到这个内存映射:
00802000 B __bss_start
00802000 D __data_end
00802000 D __data_start
00802000 D _edata
00802000 00000002 b n.4418
00802002 00000001 b packetEnd.1686
00802003 00000002 b byteCount.1684
00802005 00000002 b StepsCounted.4253
00802007 00000001 b ErrorCode.4252
00802008 00000001 b SuccessNb.4251
00802009 00000001 b ReturnNb.4250
0080200a 00000004 b stepsOutOpto.4211
0080200e 00000004 b HomingError.4212
00802012 00000008 b stepscounted.4210
0080201a 00000004 b CntHomeState.4209
0080201e 00000001 b byteCount.4166
0080201f 00000002 B EjectMsgID
00802021 00000001 B VersionMinor
00802022 00000002 B QueueEnd
00802024 00000001 B VersionMonth
00802025 00000001 B ACC1_IN
00802026 0000001f B PacketQRx
00802045 0000001f B PacketTx
00802064 00000001 B VersionMajor
00802065 00000001 B DeviceTypeId
00802066 00000001 B debugCycler_bytes
00802067 00000001 B debugAXIS_ACK
00802068 000000d4 B AXIS
0080213c 00000001 B LVL_SENSE_IN
0080213d 00000001 B LID_DETECTION_ON
0080213e 00000001 B readyimmediateTx
0080213f 0000001f B PacketQTx
0080215e 00000004 B RobotSerialNumber
00802162 00000001 B USBIN
00802163 00000001 B startupComplete
00802164 000007c0 B PacketQueue
00802924 0000001f B PacketRx
00802943 00000001 B ACC2_IN
00802944 00000002 B QueueNb
00802946 00000001 B QueuedCommandCalled
00802947 0000001f B dummyPkt
00802966 00000001 B CYCLER_IN
00802967 00000002 B QueueStart
00802969 00000001 B HardwareRevision
0080296a 00000001 B VersionYear
0080296b 00000980 B AXISRxFIFO
008032eb 00000004 B RTS
008032ef 00000980 B AXISTxFIFO
00803c6f 00000068 B AXIS_SPI_Tx_Packet
00803cd7 00000004 B ReturnPacketMissed
00803cdb 00000068 B AXIS_SPI_Rx_Packet
00803d43 00000004 B NbPacketsInAxisFIFO
00803d47 00000100 B CyclerEEPROM
00803e47 00000260 B TxFIFO
008040a7 00000260 B RxFIFO
00804307 B __bss_end
注意:我使用nm
命令nm -S -n MotorBoard\ Xmega\ Large\ FIFO.elf
时使用此地图的方式。第一列是地址,第二列是变量的大小。
ATMEL ATxmega128A1 Datasheet表示在0x2000
和0x3FFF
之间有8KB的SRAM。正如您所看到的,FIFO缓冲区与0x3FFF
限制重叠0x3E47
TxFIFO
和0x40A7
RxFIFO
重叠。
解决问题的一种方法是将一些变量声明为const
。例如,我可以看到VersionMonth
,VersionMajor
可能是不变的。
答案 1 :(得分:0)
没有。只是没有。
你的观念是错误的。使用FIFO缓冲区时, 只能在程序中使用一个写入和一个读取点。在你的情况下,写入将在 UART RX 中,并且例如在程序的while (1)
循环中读取。
这是足够的结构信息:
#define FIFO_SIZE 100
typedef struct {
uint16_t Write, Read;
uint8_t Buffer[FIFO_SIZE];
} FIFO;
然后你需要2个(更好的3个)功能:
实现类似于:
void FIFO_Init(FIFO* f) {
f->Write = 0;
f->Read = 0;
}
//This function needs check if buffer is full, will update it.
void FIFO_Write(FIFO* f, uint8_t ch) {
//Check here if buffer is full first
f->Buffer[f->Write++] = ch;
if (f->Write >= FIFO_SIZE) {
f->Write = 0;
}
}
uint8_t FIFO_Read(FIFO* f, uint8_t* ch) {
volatile uint16_t write = f->Write, read = f->Read;
if (write == read) {
return 0; //FIFO empty, return 0
}
*ch = f->Buffer[f->Read++];
if (f->Read >= FIFO_SIZE) {
f->Read = 0;
}
return 1; //character is valid
}
写作和阅读的功能现在彼此安全。您可以从IRQ或任何地方写信,同时阅读而不必担心。
您可以轻松地在内部使用FIFO_Write,当您从FIFO读取时,您不需要禁用中断。这就是FIFO的目的。单写点,单读点。
希望它有所帮助。