Проблемы распределения памяти для буфера сообщений - PullRequest
1 голос
/ 16 октября 2019

Я пытаюсь использовать статические структуры в качестве буфера для входящих сообщений, чтобы избежать проверки буфера на внешнем модуле MCP2515. ISR входит в функцию со значением 255 can_message *, чтобы фактически прочитать новые сообщения из моего MCP2515. Другие приложения регистрируют идентификатор в сообщении, передаваемом в качестве аргумента, чтобы проверить, содержит ли буфер какие-либо сообщения с таким же значением. Это возвращает неправильные идентификаторы, а остальные поля данных равны 0 и неинициализированы. Что не так?

can_message struct:

typedef struct 
{
    uint8_t id;
    uint8_t datalength;
    uint8_t data[8];
}can_message;
int CAN_message_receive(can_message* message)
{

    static volatile can_message* buffers = (volatile can_message*)0x18FF;
    static int birth = 1;
    if(birth)
    {
        for (int i; i < CAN_MESSAGE_UNIQUE_IDS; i++)
        {
                        //These structs gets addresses outside SRAM
            buffers[i] = (can_message){0,0,0};
        }
        birth = 0;
    }

    if (message == CAN_UPDATE_MESSAGES)
    {
        /* Sorts messages <3 */
        can_message currentMessage;
                //These functions are working:
        CAN_message_get_from_MCP_buf(&currentMessage, 0);
        buffers[currentMessage.id] = currentMessage;
        CAN_message_get_from_MCP_buf(&currentMessage, 1);
        buffers[currentMessage.id] = currentMessage;


        return 0;   //returns nothing !
    }
    if(buffers[message->id].id != 0)
    {
        printf("test\n");
                //This copy gives wrong id and data:
        memcpy(message, &buffers[message->id], sizeof(can_message));
        buffers[message->id].id = 0;
        return 0;
    }
    return -1;
} 

Редактировать 1: Однако я заметил, что любая структура буферов [i] получает совершенно другой адрес, чем ожидалось. Он не использует адреса, следующие за 0x18FF на SRAM. Есть ли способ изменить это?

Редактировать 2: Это мой основной цикл:

while (1) {

//printf("tx buf ready: %d\n", MCP2515_TX_buf_empty(0));
//CAN_Loopback_test();

_delay_ms(500);
        value = USART_ReadByte(0);
        CAN_message_receive(&msg);
        printf("CAN_receive: ID: %d, datalength: %d, data: \n",msg.id);
        for (int k; k < msg.datalength; k++)
        {
            printf("%d, ",msg.data[k]);
        }
        printf("\n");

    }

Редактировать 3: Изменение указателя буфера на массив решило проблему. (Он больше не использует SRAM, но все, что плавает в моей лодке)

int CAN_message_receive(can_message* message)
{

    static can_message buffers[CAN_MESSAGE_UNIQUE_IDS];
    static int birth = 1;
    if(birth)
    {
        for (int i; i < CAN_MESSAGE_UNIQUE_IDS*10; i++)
        {
            *(char*)(0x18FF+i) = 0;
            printf("buffers: %X\n", &buffers[i]);
        }
        birth = 0;
    }

Ответы [ 2 ]

0 голосов
/ 16 октября 2019

Я бы настоятельно рекомендовал отделить логику ISR от собственной логики кэша сообщений. Также логика инициализации с переменной birth выглядит ненужной.

Я бы настроил некоторый кольцевой буфер, чтобы ISR мог записывать сообщения, и из этого основной код считывает данные в буфер поиска ID.

Это будет гарантировать, что обновления сообщений не будутмешает считыванию (по крайней мере, если вы проверяете индексы чтения / записи в кольцевой буфер), а также устраняет необходимость помещать мьютексы вокруг всего буфера сообщений.

В настоящее время он очень плохо пахнет из-за отсутствия чтения / записисинхронизация.

// global
#define CAN_MESSAGE_UNIQUE_IDS 50
static can_message g_can_messagebuffers[CAN_MESSAGE_UNIQUE_IDS];

#define MAX_RECEIVEBUFFER 8
static volatile can_message g_can_ringbuffer[MAX_RECEIVEBUFFER];
static volatile int g_can_ringbufferRead  = 0;
static volatile int g_can_ringbufferWrite = 0;


// called from ISR
void GetNewMessages()
{
    // todo: check ring buffer overflow
    can_message currentMessage;
    CAN_message_get_from_MCP_buf(&g_can_ringbuffer[g_can_ringbufferWrite], 0);
    g_can_ringbufferWrite = (g_can_ringbufferWrite + 1) % MAX_RECEIVEBUFFER;

    CAN_message_get_from_MCP_buf(&g_can_ringbuffer[g_can_ringbufferWrite], 1);
    g_can_ringbufferWrite = (g_can_ringbufferWrite + 1) % MAX_RECEIVEBUFFER;
}


// called from main loop
void handleNewMessages()
{
  while(g_can_ringbufferRead  != g_can_ringbufferWrite){
    const can_message* currentMessage = &g_can_ringbuffer[g_can_ringbufferRead];
    if(currentMessage->id < CAN_MESSAGE_UNIQUE_IDS)
    {
      g_can_messagebuffers[currentMessage->id] = *currentMessage;
    }        
    g_can_ringbufferRead  = (g_can_ringbufferRead  + 1) % MAX_RECEIVEBUFFER;
  }
}

// called from whoever wants to know
// todo: 
//    really required a by value interface?
//    would it not be sufficient to return a pointer and
//    provide an additional interface to mark the message as used?
int getMsg(can_message* message)
{
  if(buffers[message->id].id != 0)
  {
    printf("test\n");
    *message =  &g_can_messagebuffers[message->id];
    g_can_messagebuffers[message->id].id = 0;
    return 0;
  }
  return -1;
}

// alternative to above 
const can_message* getMsg(int id)
{
  if(    (id < CAN_MESSAGE_UNIQUE_IDS)
      && (g_can_messagebuffers[id] != 0))
  {
    return &g_can_messagebuffers[id].id;
  }
  return NULL;
}

void invalidateMsg(int id)
{
  if(id < CAN_MESSAGE_UNIQUE_IDS)
  {
     g_can_messagebuffers[id] = 0;
  }
}

edit:
после ваших изменений в массиве сообщений вместо какого-то странного указателя, также нет необходимости в процедуре установки для этого кода.

edit:
если в вашем микроконтроллере уже есть буфер для принятых сообщений, то, возможно, вообще не нужно регистрировать ISR, и вы можете очистить его из основного цикла непосредственно в свой собственный буфер поиска идентификатора (при условии, что основной цикл достаточно быстр)

0 голосов
/ 16 октября 2019

Решено! Указатель на буферы изменен на буфер-массив:

int CAN_message_receive(can_message* message)
{

    static can_message buffers[CAN_MESSAGE_UNIQUE_IDS];
    static int birth = 1;
    if(birth)
    {
        for (int i; i < CAN_MESSAGE_UNIQUE_IDS*10; i++)
        {
            *(char*)(0x18FF+i) = 0;
            printf("buffers: %X\n", &buffers[i]);
        }
        birth = 0;
    }
...