문제

임베디드 시스템에는 진단 목적으로 명령 줄 인터페이스를 통해 임의의 데이터를 읽을 수있는 설정이 있습니다. 대부분의 데이터에 대해서는 제대로 작동하며 사용합니다. memcpy() 요청 된 주소로 데이터를 복사하고 직렬 연결을 통해 다시 보냅니다.

그러나 16 비트 하드웨어 레지스터의 경우 memcpy() 몇 가지 문제가 발생합니다. 두 개의 8 비트 액세스를 사용하여 16 비트 하드웨어 레지스터에 액세스하려고하면 고차 바이트가 올바르게 읽지 않습니다.

이 문제를 겪은 사람이 있습니까? 나는 하드웨어에 가까워지고있는 '높은 수준'(c#/java/python/ruby) 남자입니다. 이것은 외계인 영역입니다.

이것을 다루는 가장 좋은 방법은 무엇입니까? 나는 어떤 정보, 구체적으로, 다소 혼란스러운 [나에게] 게시물을 본다. 여기. 이 게시물의 저자는 있습니다 바로 그거죠 내가하는 것과 같은 문제이지만 내가하고있는 일을 완전히 이해하지 않고 솔루션을 구현하는 것을 싫어합니다.

이 문제에 대해 흘릴 수있는 빛은 대단히 감사합니다. 감사!

도움이 되었습니까?

해결책

무엇을 외에도 에디가 말했다, 일반적으로 휘발성 포인터를 사용하여 하드웨어 레지스터를 읽어야합니다 (메모리 매핑 레지스터를 가정하면 모든 시스템의 경우는 아니지만 귀하에게는 사실입니다). 같은 것 :

// using types from stdint.h to ensure particular size values
// most systems that access hardware registers will have typedefs
// for something similar (for 16-bit values might be uint16_t, INT16U,
// or something)

uint16_t volatile* pReg = (int16_t volatile*) 0x1234abcd;  // whatever the reg address is

uint16_t val = *pReg;  // read the 16-bit wide register

다음은 Dan Saks의 일련의 기사입니다. C/C ++에서 메모리 매핑 레지스터를 효과적으로 사용할 수 있도록 알아야 할 모든 것을 제공해야합니다.

다른 팁

이 하드웨어의 각 레지스터는 2 바이트 어레이로 노출되며 첫 번째 요소는 2 바이트 경계에서 정렬됩니다 (주소는 짝수). memcpy ()는 사이클을 실행하고 각 반복마다 하나의 바이트를 복사 하므로이 레지스터에서 이런 식으로 복사합니다 (모든 루프가 무너지고 char는 하나의 바이트입니다).

*((char*)target) = *((char*)register);// evenly aligned - address is always even
*((char*)target + 1) = *((char*)register + 1);//oddly aligned - address is always odd

그러나 두 번째 줄은 일부 하드웨어 특정 이유로 잘못 작동합니다. 한 번에 하나씩 한 번에 두 바이트를 복사하면 대신이 방법으로 수행됩니다 (짧은 int는 두 바이트입니다).

*((short int*)target) = *((short*)register;// evenly aligned

여기서 한 번의 작업에 두 바이트를 복사하고 첫 바이트는 균등하게 정렬됩니다. 이상하게 정렬 된 주소에서 별도의 복사가 없으므로 작동합니다.

수정 된 Memcpy는 주소가 정렬되어 있는지 여부를 확인하고 Tow Bytes 덩어리가있는 경우 사본을 확인합니다.

특정 크기의 하드웨어 레지스터에 액세스 해야하는 경우 두 가지 선택이 있습니다.

  • C 컴파일러가 코드를 생성하는 방법을 이해하여 적절한 정수 유형을 사용하여 메모리에 액세스하거나
  • 올바른 바이트 또는 단어 크기로 액세스 할 수 있도록 일부 어셈블리를 포함시킵니다.

물론 레지스터 및 기능에 따라 하드웨어 레지스터를 읽으면 부작용이 발생할 수 있으므로 적절한 크기의 액세스로 하드웨어 레지스터에 액세스하여 전체 레지스터를 한 번에 읽을 수 있습니다.

일반적으로 레지스터와 같은 크기의 정수 유형을 사용하는 것만으로도 충분합니다. 에 대부분 컴파일러, 짧은 비트는 16 비트입니다.

void wordcpy(short *dest, const short *src, size_t bytecount)
{
    int i;
    for (i = 0;  i < bytecount/2;  ++i)
        *dest++ = *src++;
}

나는 모든 세부 사항이 당신이 게시 한 스레드에 포함되어 있다고 생각합니다.

구체적으로;

If you access a 16-bit hardware register using two 8-bit
accesses, the high-order byte doesn't read correctly (it
always read as 0xFF for me). This is fair enough since
TI's docs state that 16-bit hardware registers must be
read and written using 16-bit-wide instructions, and
normally would be, unless you're using memcpy() to
read them.

따라서 여기서 문제는 하드웨어 레지스터가 단일 16 비트 읽기에서 값을 읽는 경우에만 올바른 값을보고한다는 것입니다. 이것은하는 것과 같습니다.

uint16 value = *(regAddress);

이것은 단일 16 바이트 읽기를 사용하여 주소에서 값 레지스터로 읽습니다. 반면에 한 번에 단일 바이트를 복사하는 Memcpy가 있습니다. 같은 것;

while (n--)
{
  *(uint8*)pDest++ = *(uint8*)pSource++;
}

따라서 레지스터가 한 번에 8 비트 (1 바이트)를 읽게하여 값이 유효하지 않습니다.

해당 스레드에 게시 된 솔루션은 소스와 대상이 A6 비트 정렬되는 곳마다 16 비트 읽기를 사용하여 데이터를 복사하는 Memcpy 버전을 사용하는 것입니다.

무엇을 알아야합니까? 당신은 이미 그것을 설명하는 별도의 게시물을 찾았습니다. 분명히 CPU 문서 필요합니다 16 비트 하드웨어 레지스터는 16 비트 읽기 및 쓰기로 액세스하지만 Memcpy의 구현에는 8 비트 판독/쓰기를 사용합니다. 그래서 그들은 함께 일하지 않습니다.

솔루션은 단순히이 레지스터에 액세스하기 위해 Memcpy를 사용하지 않는 것입니다. 대신 16 비트 값을 복사하는 자신의 일상을 작성하십시오.

질문이 무엇인지 정확히 모르겠습니다. 게시물에 올바른 솔루션이 있다고 생각합니다. 당신이 언급했듯이, 문제는 표준 memcpy () 루틴이 한 번에 바이트를 읽고 메모리 매핑 하드웨어 레지스터에 대해 올바르게 작동하지 않는다는 것입니다. 이는 프로세서의 한계입니다. 시간에 바이트를 읽는 유효한 값을 얻을 수있는 방법이 없습니다.

제안 된 솔루션은 단어가 정렬 된 주소로만 작동하는 자신의 memcpy ()를 작성하고 한 번에 16 비트 단어를 읽는 것입니다. 이것은 매우 간단합니다. 링크는 AC와 어셈블리 버전을 모두 제공합니다. 유일한 gotcha는 유효하게 정렬 된 주소에서 항상 16 비트 사본을 수행하는 것입니다. 링커 명령 또는 프라그마를 사용하여 물건이 정렬되었는지 확인하거나 정렬되지 않은 버퍼 앞면의 추가 바이트에 대한 특별한 케이스를 추가하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top