Создать варианты жестко заданных определений - PullRequest
2 голосов
/ 05 мая 2019

У меня есть исходный код C для микроконтроллера, и я покажу вам первую часть заголовка:

#define USART_RX_BUFFER_SIZE 256
#define USART_TX_BUFFER_SIZE 256
#define USART_RX_BUFFER_MASK (USART_RX_BUFFER_SIZE - 1)
#define USART_TX_BUFFER_MASK (USART_TX_BUFFER_SIZE - 1)

#if (USART_RX_BUFFER_SIZE & USART_RX_BUFFER_MASK)
#error RX buffer size is not a power of 2
#endif
#if (USART_TX_BUFFER_SIZE & USART_TX_BUFFER_MASK)
#error TX buffer size is not a power of 2
#endif

typedef struct USART_Buffer {
    volatile uint8_t RX[USART_RX_BUFFER_SIZE];
    volatile uint8_t TX[USART_TX_BUFFER_SIZE];
    volatile uint16_t RX_Head;
    volatile uint16_t RX_Tail;
    volatile uint16_t TX_Head;
    volatile uint16_t TX_Tail;
} USART_Buffer_t;

typedef struct Usart_and_buffer {
    USART_t *usart;
    USART_DREINTLVL_t dreIntLevel;
    USART_TXCINTLVL_t txcIntLevel;
    USART_Buffer_t buffer;
    PORT_t *rs485_Port;
    uint8_t  rs485_Pin;
    bool rs485;
} USART_data_t;

uint8_t USART_RXBuffer_GetByte(USART_data_t *usart_data);
bool USART_RXComplete(USART_data_t *usart_data);
void USART_TransmitComplete(USART_data_t *usart_data);
...

Есть несколько других подобных функций. В их реализации часто используются USART_data_t и USART_Buffer_t, пример:

bool USART_TXBuffer_PutByte(USART_data_t *usart_data, uint8_t data) {
    uint8_t tempCTRLA;
    uint16_t tempTX_Head;
    bool TXBuffer_FreeSpace;
    USART_Buffer_t * TXbufPtr;

    if (usart_data->rs485) usart_data->rs485_Port->OUTSET = usart_data->rs485_Pin;
    TXbufPtr = &usart_data->buffer;
...

В моих реальных приложениях мне нужно объявить много структур USART_data_t, но только для нескольких из них требуется такой большой буфер (256 байт). Большинство будет работать с очень маленькими, такими как 64 или даже 32 байта.

Мне легко не хватает памяти, и все это пространство фактически не используется.

Моя цель - найти способ сэкономить место.

Грязный способ - клонировать весь файл, переименовать все переменные / функции, чтобы получить две разные версии, скажем, одну с буферами по 256 байт, а другую с буферами по 64 байта. Но тогда мне также придется менять каждый вызов в моем коде, и я бы этого избегал.

Эта библиотека очень быстрая, потому что она работает с кольцевыми буферами с величиной степени 2, и, используя приведенные выше определения, требуется всего несколько тактов для выполнения требуемой математики. Поэтому я действительно не хочу переписывать всю библиотеку, чтобы использовать динамическое распределение памяти.

Есть еще идеи?

Пример использования:

USART_data_t RS232B_USART_data;
USART_data_t RS232A_USART_data;

#define RS232B_BUFFER_SIZE                  4
char RS232B_RxBuffer[RS232B_BUFFER_SIZE];
char RS232B_TxBuffer[RS232B_BUFFER_SIZE];

#define RS232A_BUFFER_SIZE                  64
char RS232A_RxBuffer[RS232A_BUFFER_SIZE];
char RS232A_TxBuffer[RS232A_BUFFER_SIZE];

ISR(USARTC1_RXC_vect) { USART_RXComplete(&RS232B_USART_data); }
ISR(USARTC1_DRE_vect) { USART_DataRegEmpty(&RS232B_USART_data); }
ISR(USARTC1_TXC_vect) { USART_TransmitComplete(&RS232B_USART_data); }

ISR(USARTD0_RXC_vect) { USART_RXComplete(&RS232A_USART_data); }
ISR(USARTD0_DRE_vect) { USART_DataRegEmpty(&RS232A_USART_data); }
ISR(USARTD0_TXC_vect) { USART_TransmitComplete(&RS232A_USART_data); }

// ...

USART_InterruptDriver_Initialize(&RS232B_USART_data, &RS232B_USART, USART_DREINTLVL_LO_gc, USART_TXCINTLVL_LO_gc, false);
USART_Format_Set(RS232B_USART_data.usart, USART_CHSIZE_8BIT_gc, USART_PMODE_DISABLED_gc, false);
USART_RxdInterruptLevel_Set(RS232B_USART_data.usart, USART_RXCINTLVL_HI_gc);
USART_Baudrate_Set(&RS232B_USART, 2094, -7);
USART_Rx_Enable(RS232B_USART_data.usart);
USART_Tx_Enable(RS232B_USART_data.usart);

USART_InterruptDriver_Initialize(&RS232A_USART_data, &RS232A_USART, USART_DREINTLVL_LO_gc, USART_TXCINTLVL_LO_gc, false);
USART_Format_Set(RS232A_USART_data.usart, USART_CHSIZE_8BIT_gc, USART_PMODE_DISABLED_gc, false);
USART_RxdInterruptLevel_Set(RS232A_USART_data.usart, USART_RXCINTLVL_HI_gc);
USART_Baudrate_Set(&RS232A_USART, 2094, -7);
USART_Rx_Enable(RS232A_USART_data.usart);
USART_Tx_Enable(RS232A_USART_data.usart);

1 Ответ

0 голосов
/ 06 мая 2019

Вы можете переписать USART_Buffer_t, чтобы он содержал только указатель на буферы rx / tx и добавил две дополнительные переменные, которые установлены в размере «прикрепленных» буферов.

Это все только что записано, так что ожидайте опечаток и т. Д., Но я надеюсь, что вы поняли .:

typedef struct USART_Buffer {
    volatile uint8_t* pRX;
    volatile uint8_t* pTX;
    volatile uint16_t RX_Size;
    volatile uint16_t TX_Size;
    volatile uint16_t RX_Head;
    volatile uint16_t RX_Tail;
    volatile uint16_t TX_Head;
    volatile uint16_t TX_Tail;
} USART_Buffer_t;

Затем вы пишете вспомогательную функцию, такую ​​как

USART_InitBuffers(USART_data_t data, uint8_t* pTxBuffer, uint16_t sizeTxBuffer, uint8_t* pRxBuffer, uint16_t sizeRxBuffer) {
     data.pRX = pTxBuffer;
     // ... other assignments
}

Таким образом, вы можете указать свои массивы разного размера для каждого USART:

uint8_t TxData1[100]
uint8_t RxData1[10]
uint8_t TxData2[255]
uint8_t RxData2[50]

USART_Buffer_t data1;
USART_Buffer_t data2;

main() {
    USART_InitBuffers(&data1, TxData1, sizeof(TxData1), RxData1, sizeof(RxData1));
    USART_InitBuffers(&data2, TxData2, sizeof(TxData2), RxData2, sizeof(RxData2));
}

В конце концов, вам нужно настроить функции библиотеки, чтобы использовать RX_Size и TX_Size вместо использования USART_RX_BUFFER_SIZE и USART_TX_BUFFER_SIZE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...