STM32 MCU는 칩마다 각각 다른 96bit(12-Byte)의 고유번호(Unique ID)를 갖고 있다.


이 고유 번호는 종종 쓸모가 있다. 
- 1회용 싸구려 소모품이 아닌 이상, 제품 마다 이력 관리를 할 수도 있고,
- 가공 해서 암호를 만들 수도 있으며,
- 무선 장비의 경우에는 맥어드레스라고 하여, 서로 간의 통신할 때 충돌을 방지하는 용도로도 사용할 수 있다.


고유 번호가 없을 경우, 칩마다 각각 플래쉬 메모리에 서로 다른 번호를 만들어서 넣어 줘야 하는데,
여간 불편한 게 아니다.

고유 아이디를 만드려면, 코드에 직접 넣어서 컴파일해서 MCU에 프로그램해서 넣는 방법과 
통신을 통해서 프로토콜로 플래쉬의 특정 주소에 써 넣는 방법이 주로 사용될 것이다.

고유 아이디를 만들어서 플래쉬에 쓰는 경우에는, 
플래쉬에 썼기 때문에 잘못해서 지워지는 경우가 있을 수 있고, 
사람이 하다 보니 중복해서 쓰거나 안 쓰고 넘어가는 경우도 종종 있다.

또한 칩 하나하나 마다 컴파일을 하거나 통신 프로토콜로 아이디를 쓰려면 툴을 사용해야 하고 시간도 많이 걸리니 모든것이 낭비여서, 고유 아이디가 제공된다는 점은 어떻게 보면 큰 장점이다.

STM32F4 MCU 에서 제공된 고유 아이디를 읽으려면, 고유 아이디가 위치한 특정 어드레스에서 값을 읽으면 된다.

아주 간단한 예로 끝내겠다. 
다음 예는 유니크 아이디가 위치한 주소(0x1FFF7A10)에서 12바이트를 
8비트/16비트/32비트 단위로 읽어서 각각 UART로 출력하는 예이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    #define ID_UNIQUE_ADDRESS        0x1FFF7A10
 
    uint8_t i;
    uint8_t uu_id_8b[12];
    uint16_t uu_id_16b[6];
    uint32_t uu_id_32b[3];
    
    // 8-bit 12-EA Read
    for (i=0;i<12;i++)
        uu_id_8b[i] = *(uint8_t *)(ID_UNIQUE_ADDRESS+i);
    // 16-bit 6-EA Read
    for (i=0;i<6;i++)
        uu_id_16b[i] = *(uint16_t *)(ID_UNIQUE_ADDRESS+i*2);
    // 32-bit 3-EA Read
    for (i=0;i<3;i++)
        uu_id_32b[i] = *(uint32_t *)(ID_UNIQUE_ADDRESS+i*4);
 
    printf("UUID[8-Bit]  ");
    for(i=0;i<12;i++)
        printf(":%02X",uu_id_8b[i]);
 
    printf("\n\rUUID[16-Bit] ");
    for(i=0;i<6;i++)
        printf(":%04X",uu_id_16b[i]);
 
    printf("\n\rUUID[32-Bit] ");
    for(i=0;i<3;i++)
        printf(":%08X",uu_id_32b[i]);
 
    while(1);
cs





참고로 다음과 같은 정보도 있다.
읽는 방식은 메뉴얼을 참고로 위의 코드 예를 조금 변경하면 되겠고, 
더 자세한 정보는 링크에 가서 코드를 다운 받아서 보면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * @brief  Get STM32F4xx device signature
 * @note   Defined as macro to get maximal response time
 * @param  None
 * @retval Device signature, bits 11:0 are valid, 15:12 are always 0.
 *           - 0x0413: STM32F405xx/07xx and STM32F415xx/17xx)
 *           - 0x0419: STM32F42xxx and STM32F43xxx
 *           - 0x0423: STM32F401xB/C
 *           - 0x0433: STM32F401xD/E
 *           - 0x0431: STM32F411xC/E
 */
/**
 * @brief  Get STM32F4xx device revision
 * @note   Defined as macro to get maximal response time
 * @param  None
 * @retval Device revision value
 *           - 0x1000: Revision A
 *           - 0x1001: Revision Z
 *           - 0x1003: Revision Y
 *           - 0x1007: Revision 1
 *           - 0x2001: Revision 3
 */
#define ID_DBGMCU_IDCODE        0xE0042000
 
 
/**
 * @brief  Get STM32F4xx device's flash size in kilo bytes
 * @note   Defined as macro to get maximal response time
 * @param  None
 * @retval Flash size in kilo bytes
 */
#define ID_FLASH_ADDRESS        0x1FFF7A22
cs




------------------------------------------------------------------------------------------------





------------------------------------------------------------------------------------------------




이번에는 u-Sdcard FTP Server 를 만들기 전에 u-SD Card가 제대로 동작하는지를 보기 위해,

Sd-card 예제(SD-esp8266->ReadWrite)를 테스트해 봤습니다.




연결은 ESP8266 의 HSPI 포트에 연결을 하고, /CS는 일반 GPIO 핀인 GPIO04 에 연결했습니다.
즉, ESP8266 의 다음과 같은 핀을 사용해서 SPI 방식으로 u-SD Card를 제어합니다.
sd-card는 예전에 샀던 u-sdcard 소켙 보드를 이용해서 esp8266과 붙였습니다.
1. SCK (HSCLK:GPIO14)
2. MISO (HMISO:GPIO12)
3. MOSI (HMOSI:GPIO13)
4. /CS (GPIO04)




NODE MCU V3 보드의 핀헤더에 u-Sdcard 와 SPI로 연결되는 핀을 다시 자세히 표시해 봤습니다.




이렇게 연결한 실제 보드의 모습은 다음과 같습니다.




이렇게 연결하고 아두이노 IDE 환경에서 프로그램을 컴파일하고 프로그램을 업로드하면 
test.txt 파일이 Sd-card에 만들어 지고, Esp-8266을 리셋 할 때마다 test.txt 에 testing 1, 2, 3, 이 계속 추가됩니다.

SD-Card를 리더에 의해 읽어 보니 위에서 말한 동작이 잘 수행됐음을 알 수 있습니다.





이렇게 SD-Card가 ESP-8266 에 연결이 잘 되었고, 동작도 잘 되었음을 알 수 있었습니다.



ESP8266 에서 EEPROM 은 실제로는 없고 외부에 있는 SPIFF 플래쉬 메모리의 일부를 사용하는 것이다.


EEPROM 을 다루는 함수들은 Library 에 있는 EEPROM.cpp 에 정의되어 있다.
라이브러리 소스의 위치는 다음과 같다.
C:\Users\trion\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\libraries\EEPROM

함수들의 종류는 다음과 같다.
1. void EEPROMClass::begin(size_t size)
   : 예를 들어 아두이노 스케치 코드에서 begin.EEPROM(512); 라고 코딩을 하면, EEPROM 을 512바이트 할당하고,
     EEPROM 관련 항목들을 초기화한다.
2. uint8_t EEPROMClass::read(int address)
   : 위에서 예를 든 begin 함수와 같이 설명하자면, 어드레스 0~511 까지 512개의 바이트 데이터를 해당 주소에서 읽어 올 수 있다.
3. void EEPROMClass::write(int address, uint8_t value)
   : 해당 주소(address)에 값을 쓴다. 이 때, 실제로 EEPROM에 물리적으로 기록되는 것이 아니고,
     램으로 된 버퍼값을 바꾸는 것이다.
4. bool EEPROMClass::commit()
   : 실제로 물리적으로 EEPROM(외부 플래쉬 메모리)에 값을 기록해서 리셋이나 전원이 꺼져도 값을 유지할 수 있다.

다음은 아두이노 IDE 툴에서 EEPROM 을 테스트한 코드 입니다.
: NODE MCU V3.0 보드의 Flash 버튼을 누르면 EEPROM 의 0번 어드레스의 값의 0번 비트가 토글 되면서,
  값을 기록하고 소프트웨어 리셋을 이용하여 리셋을 한 후,
  EEPROM의 0번 어드레스의 값이 바뀌어 있는지 EEPROM을 읽어서 시리얼 포트에 출력해 본 테스트입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <EEPROM.h>
 
const int buttonPin = 0;     // the number of the pushbutton pin
int buttonState = 0,buttonState_old=0;         // variable for reading the pushbutton status
byte value;
 
void setup() {
  // put your setup code here, to run once:
  delay(1000);
  Serial.begin(115200);
  EEPROM.begin(512);
  pinMode(buttonPin, INPUT);
  value = EEPROM.read(0);
  Serial.println("");
  Serial.print("EEPROM value = ");
  Serial.println(value,HEX);
 
  buttonState_old = buttonState = digitalRead(buttonPin);
}
 
void loop() {
  // put your main code here, to run repeatedly:
  buttonState_old = buttonState;
  buttonState = digitalRead(buttonPin);
  if (buttonState_old != buttonState)
  {
    if (buttonState == LOW) 
    {
      value = EEPROM.read(0);
      value ^= 1;
      EEPROM.write(0, value);
      EEPROM.commit(); 
      Serial.print("Button Pressed !, EEPROM value = ");
      Serial.println(value,HEX);
      Serial.println("ESP8266 Software Reset");
      ESP.reset();
    }
  }
 
}
cs


다음은 위의 ESP8266 아두이노 IDE 스케치 코드에의해 디버그용으로 시리얼에 표시한 내용 입니다.





+ Recent posts