http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHBFEIB.html


4.7. Enabling interrupts using CPS instructions and MSR instructions

In normal applications there is no need to add any barrier instruction after using a CPS instruction to enable an interrupt:

_enable_irq(); /* Compiles to “CPSIE I” - Clear PRIMASK */

If an interrupt was already in the pending state, the processor accepts the interrupt after the “CPSIE I” is executed. However, additional instructions can be executed before the processor enters the exception handler:

  • for Cortex-M3 or Cortex-M4, the processor can execute up to TWO additional instructions before entering the interrupt service routine

  • for Cortex-M0, the processor can execute up to ONE additional instruction before entering the interrupt service routine.

Figure 14 shows the implemented interrupt enabling delay in the Cortex-M3 and Cortex-M4 processors.

Figure 14. Implemented interrupt enabling delay in the Cortex-M3 and Cortex-M4 processors

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Figure 15 shows the implemented interrupt enabling delay in the Cortex-M0 and Cortex-M0+ processors.

Figure 15. Implemented interrupt enabling delay in the Cortex-M0 and Cortex-M0+ processors

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Architectural requirements

ARM recommends that the architectural requirements are adopted.

  • If it is necessary to ensure a pended interrupt is recognized before subsequent operations, the ISB instruction should be used after CPSIE I. Figure 16 shows the use of the ISB instruction after enabling interrupts to permit immediate recognition of the pending interrupt.

  • If it is not necessary to ensure that a pended interrupt will be recognized immediately before subsequent operations, it is not necessary to insert a memory barrier instruction.

  • Between two time critical tasks, if you want to permit a pended interrupt to take place, you can use an ISB instruction as follows:

    __enable_irq(); // CPSIE I : Enable interrupt
    __ISB(); // Allow pended interrupts to be recognized
    __disable_irq(); // CPSID I : Disable interrupt
    

    Figure 16 shows the resulting behavior.

    Figure 16. Use ISB after enabling interrupts to permit immediate recognition of a pending interrupt

    To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


    A suitable architectural coding is:

    To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.

    Figure 17 shows the resulting behavior.

    Figure 17. Architectural interrupt behavior between CSPIE and CPSID

    To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Note

The same requirement applies when using the MSR instruction to enable interrupts.

Implementation requirements

In Cortex-M processors:

  • If it is necessary to ensure a pended interrupt is recognized before subsequent operations, the ISB instruction should be used after CPSIE I. This is the same as the architectural requirement, see Figure 16.

  • If it is not necessary to ensure that a pended interrupt is recognized immediately before subsequent operations, it is not necessary to insert a memory barrier instruction.

  • An exception to this rule is the sequence CPSIE followed by CPSID. In Cortex-M processors, there is no need to insert an ISB between CPSIE and CPSID.

    A suitable implementation coding is:

    To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.

Figure 18 shows the implemented behavior.

Figure 18. Implemented behavior requires no ISB between CPSIE and CPSID

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


Note

As the implementation requirements show, there is no need to add a memory barrier instruction between __enable_irq() and __disable_irq(). However, in the architecture, if the interrupt needs to be recognized between the CPSIE and CPSID instructions, then an ISB instruction is needed. The same applies when using the MSR instruction to enable interrupts.

Posted by 쵸코케키

Optimizing Multiplayer Game Server Performance on AWS

출처 - Amazon



https://aws.amazon.com/ko/blogs/korea/optimizing-multiplayer-game-server-performance-on-aws/



Optimizing-Multiplayer-Game-Server-Performance-on-AWS.PDF


Posted by 쵸코케키

2017. 10. 26. 23:09 devel/code

arm hardfault handler


출처 : https://stackoverflow.com/questions/21293580/atmel-studio-dummy-handler



인터럽트 소스 얻어오는 방법


uint32_t phantomISR = 9999;

void Dummy_Handler(void)
{
    while(1) {
        phantomISR = __get_IPSR();
    }
}


ISR_NUMBER
This is the number of the current exception:
0 = Thread mode
1 = Reserved
2 = NMI
3 = Hard fault
4 = Memory management fault
5 = Bus fault
6 = Usage fault
7-10 = Reserved
11 = SVCall
12 = Reserved for Debug
13 = Reserved
14 = PendSV
15 = SysTick
16 = IRQ0
45 = IRQ29



SVC handler - gcc inline assembly


__attribute__((naked)) void SVC_Handler(void) {
    __asm__ __volatile__ (
    "   tst     lr, #0x4            \n\t"
    "   ite     eq                  \n\t"
    "   mrseq   r0, msp             \n\t"
    "   mrsne   r0, psp             \n\t"
    "   b   SVC_Handler_C           \n\t");
}
__attribute__((naked)) void SVC_Handler(void) {
    register unsigned int *svc_args __asm__("r0");

    __asm__ __volatile__ (
        "tst     lr, #0x4
         ite     eq
         mrseq   %0, msp
         mrsne   %0, psp" : "=r"(svc_args));

    return SVC_Handler_C(svc_args);
}



출처 : https://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/


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
41
42
43
// From Joseph Yiu, minor edits by FVH
// hard fault handler in C,
// with stack frame location as input parameter
// called from HardFault_Handler in file xxx.s
void hard_fault_handler_c (unsigned int * hardfault_args)
{
  unsigned int stacked_r0;
  unsigned int stacked_r1;
  unsigned int stacked_r2;
  unsigned int stacked_r3;
  unsigned int stacked_r12;
  unsigned int stacked_lr;
  unsigned int stacked_pc;
  unsigned int stacked_psr;
 
  stacked_r0 = ((unsigned long) hardfault_args[0]);
  stacked_r1 = ((unsigned long) hardfault_args[1]);
  stacked_r2 = ((unsigned long) hardfault_args[2]);
  stacked_r3 = ((unsigned long) hardfault_args[3]);
 
  stacked_r12 = ((unsigned long) hardfault_args[4]);
  stacked_lr = ((unsigned long) hardfault_args[5]);
  stacked_pc = ((unsigned long) hardfault_args[6]);
  stacked_psr = ((unsigned long) hardfault_args[7]);
 
  printf ("\n\n[Hard fault handler - all numbers in hex]\n");
  printf ("R0 = %x\n", stacked_r0);
  printf ("R1 = %x\n", stacked_r1);
  printf ("R2 = %x\n", stacked_r2);
  printf ("R3 = %x\n", stacked_r3);
  printf ("R12 = %x\n", stacked_r12);
  printf ("LR [R14] = %x  subroutine call return address\n", stacked_lr);
  printf ("PC [R15] = %x  program counter\n", stacked_pc);
  printf ("PSR = %x\n", stacked_psr);
  printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));
  printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));
  printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));
  printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));
  printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));
  printf ("SCB_SHCSR = %x\n", SCB->SHCSR);
  
  while (1);
}


Posted by 쵸코케키


dst_addr & ~(region - 1)


이렇게 하면 & 연산하는 쪽의 영역이 모두 111111bit가 되어서 dst_addr이 해당 영역 이내인지 체크 가능

.....인데 생각해보니까 그냥 > 로 크기 비교 하면 혼나나?

Posted by 쵸코케키

예를 들면 512B로 aligned 인지 확인


int check_if_aligned(unsigned long addr)

{

const unsigned long align_size = 512;

return (addr & (align_size - 1)) ? -1 : 0;                //0: aligned, -1: not aligned

}


512보다 작은 크기의 bit가 단 하나라도 & 연산으로 걸리는게 있으면 aligned가 아님

무조건 512의 배수만 &연산이 false뜸


잘 이해가 안 가면 계산기 놓고 해보면 아하~!

Posted by 쵸코케키

둘 다 1년정도 써봤다

개발하며 느낀 점을 정리해본다.


ST - STM32F4 시리즈 -  CORTEX M4 기반

ATMEL - SAMV71 시리즈 - CORTEX M7 기반



IDE 무료 기준

ST - 이클립스(openstm32 라고 이클립스 기반 IDE http://www.openstm32.org/HomePage)

ATMEL - 비주얼스튜디오(Atmel Studio http://www.atmel.com/microsite/atmel-studio/)



디버깅의 강력함

Atmel Studio의 승리

모든 register 값 실시간으로 편하게 감상하며 디버깅 가능

openstm32의 경우 한수 아래의 느낌



개발의 용이함

ST

cubemx기반 기본 프레임웤을 다양한 IDE로 export 가능. 매우 안정적이며 업데이트가 지속적으로 자주 된다. 라이브러리 역시 매우 완성도 높다


ATMEL

Atmel Studio의 'START' 라는 기능을 통해 ASF라는 프레임웤 기반 소스 export 가능

Atmel Studio 7.0 기준 완성도가 너무 심각할 정도로 낮고 해결 불가능한 메모리 할당 버그 등 상용 제품 개발 불가 수준.

2017년 9월말 현재까지 미국 본사에 리포팅한지 반년 넘어가는데도 해결 기미 안 보임

업데이트 매우 느림. IDE 자체 버그가 있음

ASF...만들다 만거 많음 소스 export된거 보면 지원 안 하는 것들 많음

지금 프로젝트 무너지게 생겼음 소프트웨어 지원이 매우 심각함

다만 MCU 자체는 괜찮다는 생각이 듬



메모리 할당 버그에 대해 말을 더 해보면 프로세스 공간의 메모리 레이아웃이 정상적으로 안 잡혀서 내가 할당받고 사용하는 메모리를 신뢰할 수 없음

linker 가 생성하는 바이너리 직접 디버깅해서 수정할 자신 있으면 시도 ㄱㄱ



납기 직전인데 반년전 리포팅한 메모리 버그 결국 해결 안되서 프로젝트 무너지기 직전...답답해서 글 적어봄

Posted by 쵸코케키

얕은 지식과 편협한 사고로 작성하였습니다


지금 세상이 마치 인터넷 막 나왔을 때, 하나포스 adsl 들어왔을 때 같이 성장하고 커져가고 있는데 우리나라의 사령탑이신 구 대통령 - 박근혜씨가 무능하고 멍청한탓에 전 세계의 이런 흐름을 전혀 파악하지 못하고 딱 80년대 수준의 올림픽, 문화 수출 머 이런 생각 수준으로 열심히 해보자 이러시는데 그 덕분에 지금 울 나라가 많이 뒷쳐져있는 상태라 비상이 걸렸다.

그 전에 막대한 돈을 IT가 아니라 저물어가는 산업인 건설에 올인하신 우리의 영원한 리더 이명박 대통령............................................................


할아버지 할머니들이 아주 좋아 죽는 미국에서도 4차 산업 혁명 육성을 위해 어마어마하게 투자 지원을 하고 경제도 활발히 돌아가고있다

입에 거품을 물고 반쯤 기절하실꺼 같이 극렬히 증오하는 빨갱이들 즉 중국 공산당에서도 국가차원으로 돈을 때려 박으면서 빵빵하게 IT에 지원해주고 있는데

이런 시대 흐름을 저어어어언혀 못 쫒아 가시는 훌륭한 분들 덕분에 IT? 그거 그냥 콤퓨타 1~2년 열심히 하면 되는거 아니냐

사...삼성 갤럭시 해은드뽄 세계 쵀곤데 말야 우리나라 부지런하고 똑똑해서 할 수 있어 잠 안자고 안 먹고 어쩌고 저쩌고......

여태 뭐하고 안 했어! 빨리 TF팀 만들어서 다음달까지 만들어내!!

뭘 언제 직접 만들고 있어!! 그냥 라이브러리 그거 계약해서 사!!


노답




IOT 기기들을 위한 산업 지원

- 짜고치는 고스돕이나 수준 낮은, 형식적인 스타트업이 아니라 진짜 기술적으로 가능한 스타트업들 지원

지금도 정부 주관으로 하는 것들이 있긴 있는데 가보면ㅎㅎㅎ


전기차 및 부가 기술들(adas, lidar 등등) + 법령 개정 및 많은 논의들

- 많이 늦었으나 어차피 자율 주행 이런건 한참 뒤의 일이고 따라갈 수 있다


드론 + 법령 개정 및 많은 논의들


산업용 로봇 + IOT



단기간에 성과 안나오는데 어떻게든 해야 하는 것들

베터리 기술

ai

인간 타는 로봇




근데 문제가 있다

위의 작업에 필요한 인력들은 공무원 시험 준비하는 인물들로 채울 수가 없다

다시말해 인력이 부족하다. 쉽게 4년제 대학 졸업 시킨다고 바로 투입하기도 힘든 인력들이다. 어떻게 해야할까?


그리고 더 큰 문제가 있다.

산업구조의 커다란 개편은 어마어마한 진통을 가져온다. 수많은 실업자들을 어떻게 해야할까


게다가 무지 큰 문제가 있다.

부패 척결 및 사회 조직 정상화 그리고 회사 시스템 민주화 개혁이 필요하다


부패 척결 및 사회 기강 확립 이런거만 줄창 달려가도 1년 이상은 걸릴터

근데 또 친박 이런 애들이 미친듯이 딴지걸꺼다. 맞는 소리를 하거나 말거나 딴지를 일단 걸꺼다. 그게 정치니까. 너가 옳은건 알겠어 하지만 그걸 그냥 너가 다 해먹게 둘 수는 없어...이짓 못하게 하려면 국민이 눈을 시뻘겋게 뜨고 노려보고 있어야 한다.



빈 수레가 요란하다는데 내 머리가 그런거 같다

Posted by 쵸코케키

STMF4 시리즈 부트로더, iap 개발 팁

#0. 주의사항

작성자 컴맹임

MCU? 그거 유재석 말하는거 아니냐??

#1. 이게 왜 필요한데?

상용제품을 출시하면 펌웨어를 업데이트 해야할 일이 분명 있을 것이다.
jtag이나 st-link 라인을 실 제품에서는 제거해놓은 경우가 많고 제품을 죄다 뜯거나 할 수가 없으니 이런저런 기타 등등 문제로 uart를 통한 펌웨어 업데이트는 언젠가는 만나게 되는 문제다.

@ boot mode image

외부로 boot mode 핀을 두어 하드웨어적으로 컨트롤 할 수있게 만들면 모를까

근데 외부로 설정할 수 있는 pin을 두는 것도 size 측면에서 보면 쉬운 일은 아니다.

boot mode는 뭐 별거 아니다 pin설정 해서 평소 부팅하는 flash주소 영역으로 부팅하는게 아니라 그 외 system memory라고 불려지는(ram이 아니다) 영역으로 부팅하도록 MCU가 지원한다.

자. 그럼 그냥 uart인터럽트 핸들러 만들어서 특정 커맨드가 들어오면 펌웨어 업데이트 하도록 개발하면 되겠네라고 생각할지도 모른다.
목표는 괜찮은데 문제가 있다.

A. 펌웨어 크기가 크기 때문에 램의 용량을 벗어난다.

예를 들어 펌웨어가 200KB라고 하면 이걸 어떻게 메모리 할당 받을 수 있을까?

매우 힘들다고 할 수 있다. 그래도 메모리를 확보해서 다운 받았다고 치자

B. sector 0에 인터럽트 핸들러 코드가 있다 -_-;;;

뭔소리냐고? flash에 write할 코드가 flash에 있기 때문에 write하는 순간 인터럽트 핸들러 및 시스템 코드가 전체적으로 바보가 된다
linker descripton를 보면 이해가 빠르다.


/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 2048K
RAM (xrw)      : ORIGIN = 0x20005000, LENGTH = 288K
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    ....
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */

flash 메모리에 isr_vector 즉 인터럽트 핸들러 위치도 있고 우리가 작성한 프로그램코드 즉 text 영역도 flash에 있다
이렇기 때문에 메인 어플리케이션에서 flash를 write를 하는 순간 이 모든게 지워지고 꼬이기 때문에 ㅎㅎㅎㅎ 기기는 먹통이 될 것이다.

ram에 상주하는 ram function을 만들어도 이는 마찬가지

-> 결국 boot loader가 필요하구나!

2. 어떻게 동작하는가?

ok, boot loader가 필요한건 이해했어 그럼 어떻게 동작하는지도 알 수 있을까?

개략적인 디자인은 아래와 같다.

1. 전원 입력
2. 0x0800 0000로 이동 //flash address, 제품마다 주소다름

3. 부트로더 코드를 읽는다  
if( uart로 5초 이내에 key 입력이 있었는가? ) {  //yes
    4. uart로 펌웨어 다운로드
    5. flash write
    6. reboot
}
else {  //no
    4.  메인 어플리케이션으로 이동
}

3. Reference

http://www.st.com/en/embedded-software/stsw-stm32067.html

이곳에서 소스코드를 받을 수 있다.

적당히 자신의 환경에 맞게 수정해서 사용하면 된다.

4. 개발

A. 큰 그림 그리기

  • boot loader는 flash sector 0만 사용한다(16KB)

  • 메인 어플리케이션은 flash sector 1부터 시작한다(2MB - 16KB)

  • 메인 어플리케이션 ISR Vector table 설정 확인

  • uart로 펌웨어를 전송 받을 때 1KB 정도로 나누어 작업한다. 메모리 크기도 문제고 flash write를 혼자 너무 오래 하면 진행 상황을 알 수 없으니…

B. 개발

테스트를 위해 먼저 작게 개발하기로 함

boot loader및 main application으로 점프가 정상적으로 되는 것을 확인한 후 uart 및 flash write 기능 추가

1. boot loader에서 led on
2. boot loader에서 start 메세지 출력
3. main application으로 jump!
4. main application 동작

C. boot loader

c code

#define APPLICATION_ADDRESS (uint32_t) 0x08004000
typedef void (*fptr)(void);
fptr jump_to_app;
uint32_t jump_addr;

HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET);      //LED ON
printf("boot loader start\n");               //메세지 출력
jump_addr = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
jump_to_app = (fptr) jump_addr;

/* init user app's sp */
printf("jump!\n");
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
jump_to_app();

cube mx에서 생성하였다.

uart랑 gpio설정 정도만 유지하고 나머지는 모두 비활성화 하여 코드 크기를 최소화 했다.

linker description

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 16K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
}

flash를 sector 0의 크기만큼만 사용하도록 설정

build 후 image의 크기 역시 맞아야 한다

D. Main Application

c code

#define FLASH_BASE            0x08000000U

// system_stm32f4xx.c
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 
/* Vector Table Relocation in Internal FLASH */

//#define VECT_TAB_OFFSET  0x00
#define VECT_TAB_OFFSET  0x4000         //이 부분을 수정
/*!< Vector Table base offset field. This value must be a multiple of 0x200. */

isr vector 주소 설정을 확인한다.

iap 에서 점프 후 systick이 동작하지 않거나 하면 이 문제일 가능성이 높다.

linker description

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x8004000, LENGTH = 2032K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K
}

flash의 크기가 sector 0를 뺀 만큼 줄어든다.

2048 - 16 = 2032KB

5. 테스트

LED가 켜지고 메세지가 출력되고 main application으로 성공적으로 jump한다.

이제 uart 다운로드 및 flash write만 포팅하면 된다

의외로 금방 포팅할 수 있다. 이를 무료로 풀어주신 stm사장님께 경롓!


Posted by 쵸코케키

O_RDONLY 로 open 한 다음 write하면 당연히 퍼미션 에러 날 줄 알았는데 perror에서 Bad file descriptor 오류가 출력되더라

그런데 errno는 1 즉 EPERM이었다.


perror 버그 같은데......

glibc version 2.19, 

Posted by 쵸코케키

Android Sensor HAL Porting Guide?

0. 개발 환경 및 목표

환경

odroid c2, android 5.1.1, 심박센서

목표

i2c 통신을 하는 심박 센서를 HAL에 추가하여 android sensor service framework에서 호출해 사용할 수 있도록 포팅

코드 포팅을 완료하고 빌드하면 android에서 사용하는 so 라이브러리 파일(shared object)이 생성된다
보통 삼성, LG같은 유명 벤더의 안드로이드 휴대폰 소스코드에는 각각 센서의 소스코드까지 포함되어 있지는 않고 HAL영역은 이런 so파일로 제공된다

물론 거기에 해당 벤더에 맞게 android 소스 전체를 환경설정하는 많은 스크립트 및 설정 파일들이 있겠지만 일단 그런건 무시
그리고 작업을 완료하고나서 가능하면 cts도 돌려볼 생각이다


0. 심박 센서 통신 구조

data
\
processing
\
raw data interrupt
\ /
ioctl() poll()
\ /
/dev/i2c /sys/class/gpio/gpioxxx
\ /
SENSOR

포팅하려는 센서의 linux application과 통신하는 구조이다
별로 좋은 구조는 아니다
driver부터 새로 짜서 다 뜯어고치고 싶은데 우선 포팅이 목표이므로 그냥 진행한다
이제 우리는 linux application이 아닌 Android HAL과 통신하게 된다


1. HAL Interface 문서

https://developer.android.com/guide/topics/sensors/sensors_overview.html#sensors-identify
https://source.android.com/devices/sensors/hal-interface.html
https://source.android.com/compatibility/cts/
모든 것이 깔끔하게 정리되어 나와있다


2. 기존 sensors.cpp 구조 파악

적당히 어떻게 추가할지 흐름을 파악한다
참고 : https://source.android.com/devices/sensors/hal-interface.html

  • get_sensors_list - 새 하드웨어 정의 추가
  • struct sensors_poll_context_t - enum 추가, 새 센서 객체 생성 및 file descriptor, pipe 연결
  • handleToDriver - id에 따른 return 하는 enum값 수정
  • activate - 획득한 handle이 accelerometer인지 심박센서인지 구분하는 코드 추가 및 센서의 enable, wake pipe 구현 -> open 및 init
  • setDelay - handle 구분 코드 추가 및 센서의 setDelay 구현
  • pollEvents - handle 구분 코드 추가 및 센서의 readEvents 구현, pipe 연결 -> ioctl로 i2c read를 넣으면 되겠다


3. 새 센서 객체 파일 추가

hardware/hardkernel/libsensor/HeartRateMonitorSensor.h
hardware/hardkernel/libsensor/HeartRateMonitorSensor.cpp
hardware/hardkernel/libsensor/Android.mk - cpp 파일 추가
만약 객체를 더 생성하거나 그럴 필요가 있으면 더 추가하면 된다


4. get_sensors_list 수정 - sensors.cpp

static struct sensor_t sSensorList[] = {
    {
        .name     = "Odroid-USBIO Accelermeter Sensor", 
        ...
    },
    {
        .name    = "heartrate monitor sensor",
        .vendor = "chocokeki",
        .version = 1,
        .handle = SENSORS_HEARTRATEMONITOR_HANDLE,
        .type = SENSOR_TYPE_HEART_RATE,
        .maxRange = ,
        .resolution = ,
        .power = ,
        .minDelay =  ,
        .fifoReservedEventCount = ,
        .fifoMaxEventCount = ,
        .stringType = SENSOR_STRING_TYPE_HEART_RATE,
        .requiredPermission = SERSOR_PERMISSION_BODY_SENSORS,    //for manifest
        .maxDelay = 0,
        .flags = SENSOR_FLAG_ON_CHANGE_MODE,
    },
}

각 항목에 관해서는 이 링크를 참조할 것. 너무 방대해서 간단한 정리가 불가하다
센서 별 특징이 있으므로 스펙에 맞게 정확히 기록
아래 링크의 sensor_t 를 확인하기 바란다
https://source.android.com/devices/sensors/hal-interface.html


5. open 수정 - sensors.cpp

open이 호출되면 sensors_poll_context_t 객체가 생성된다
sensors_poll_context 객체가 생성될 때 새로운 센서 객체를 같이 생성하도록 코드를 추가하고 poll 환경 설정 정도를 해준다
SensorBase를 통해 상속을 받은 메서드들이 호출되므로 SensorBase의 구현 코드를 참조한다(SensorBase.cpp)
그리고 InputEventCircularReader 객체도 상속을 통해 생성되니 참고하기 바란다(InputEventReader.cpp)


6. 새로운 센서 객체 구현 - HeartRateMonitorSensor.h

A. 자료형

일단 SensorBase로 부터 상속을 받고 sensors.cpp에서 사용하는 method들을 동일하게 선언한다
OdroidSensor.h 참조

#ifndef ANDROID_HRM_SENSOR_H_
#define ANDROID_HRM_SENSOR_H_

#include "SensorBase.h"
#include "InputEventReader.h"
#include "sensor.h"

class HeartRateMonitorSensor : public SensorBase {
public:
    HeartRateMonitorSensor();
    virtual ~HeartRateMonitorSensor();
    virtual int readEvents(sensors_event_t* data, int count);
    ...
};
#endif

펌웨어나 driver만 개발하는 시스템 프로그래밍에 익숙하던 분들이 갑자기 c++ 상속 개념 나오고 virtual 날아다니고 하면 멘붕이 올 수 있으나 금방 적응할 수 있다
class 상속 관련 추천 링크 : http://blog.eairship.kr/175


B. 역할 분담 계획

HeartRateMonitorSensor()
변수 초기화, 장치 open, 연관된 객체들 초기화

~HeartRateMonitorSensor()
enable을 0으로 초기화 - 센서 비활성화

hasPendingEvents()
처리 못하고 pending된 이벤트 있니?

setDelay(int32_t handle, int64_t ns)
보통 sysfs를 통해 sampling frequency를 변경하는데 1.0이하의 HAL에서만 유효 -> deprecated, batch로 변경되었다
실제 구현은 하지 않기로 한다

enable(int32_t handle, int enable)
sysfs 통해 센서 활/비활성화, interrupt 활/비활성화

readEvents(sensors_event_t* data, int count)
생성자를 통해 open한 장치로부터 InputEventCircularReader 를 통해 event data를 읽어 온다
보편적인 linux의 input_event 를 사용하지 않고 /dev/i2c와 통신을 하는 방식으로 구현하기로 했으므로 InputEventCircularReader는 사용하지 않는다

C. Method 구현

HeartRateMonitorSensor()

SensorBase를 통해 상속 받은 객체들을 초기화 한다
readEvents에서 InputEventCircularReader를 사용하기 때문에 객체 초기화를 해준다 i2c dev를 읽어올 수 있도록 장치 open
pending event를 관리할 sensors_event_t 역시 초기화를 해준다
interrupt 설정 및 활성화
마지막으로 enable을 호출하여 센서를 활성화 한다

InputEventCircularReader의 버퍼 크기는 적당히 잡아준다
말 그대로 링이 구현되어 있는 것인데 struct input_event크기로 데이터를 읽어오니 주의 바란다
그런데 input_event라하면 /sys/class/input 여기인데 무조건 이런 형태로 데이터를 넣고 받아야 하는지 의문이다
레퍼런스 어디서 못 보려나

우리는 용감하게 i2c dev를 읽도록 결정하였으므로 과감하게 무시하자

~HeartRateMonitorSensor()

센서가 활성화 중인지 체크하고 enable을 호출하여 센서를 비활성화 한다
얘가 왜 virtual로 선언되어야 하는지 몰랐는데 상속 받은 아이들의 destructor는 virtual가 붙어야 한다고 하더라

hasPendingEvents()

readEvents 에서 data를 읽었는지 여부를 확인

setDelay(int32_t handle, int64_t ns)

sysfs를 통해 센서에 명령을 전달, sampling frequency를 변경
하지만 구현하지 않는다. 신 버전에서 batch로 변경되었으니까

enable(int32_t handle, int enable)

센서 활성화/비활성화 - 보통 sysfs 를 통해 명령을 내린다

readEvents(sensors_events_t* data, int count)

data에 sensors_event_t 형태의 자료를 붙여서 보내면 된다
count는 몇개 읽을까요?고 return값으로는 몇개 이벤트를 읽었는지 보내면 ok

InputEventCircularReader를 사용하는 루틴은 정형화 되어 있으므로
readEvents에서 fill하거나(read), readEvent를 호출하는 구조를 그대로 사용하면 된다

현재 구현하려는 센서가 심박센서라 input_event 모델이 딱히 필요 없기 때문에(사실 귀찮아서)
대충 간략하게 sensors_event_t를 만들어서 보내는 식으로 개발하려 한다


D. Device Driver 구현

이번에는 /dev/i2c와 통신을 하기 때문에 따로 driver를 구현할 필요는 없으나 일반적인 경우에는 InputEventCircularReader가 struct input_event 형태로 데이터를 읽어가므로 read 요청이 오면 해당 형태로 데이터를 보내주도록 한다
그런데 여기에도 함정카드가 있는데 일반적인 기법에 대해서 말이다
퀄컴 보드의 경우 sensors_classdev 라는 linux kernel device driver 영역에 자료형과 api를 만들어서 제공하며 그 규칙을 따라서 제작해야 한다
참고 : Qualcomm Snapdragon Sensors Porting Guide
https://developer.qualcomm.com/qfile/28820/lm80-p0436-9_sensors_porting_guide.pdf

nexus 5x 기준 android kernel source
drivers/sensors/sensors_class.c
drivers/input/misc/akm8963.c - compass sensor
drivers/misc/apds993x.c - ambient light, proximity sensor 등등 좋은 예시가 많다

이런 규칙을 따라 작성하는게 통일성도 유지되고 좋을 것 같다

불행히 일반적인 심박센서가 어떤 자료형으로 어떻게 통신되는지 레퍼런스를 알 길이 없으므로 일단 input_event 형태로 구현하고
driver가 데이터를 넘겨주면 hal에서는 struct heart_rate_event_t형태로 만들어 줘야할 것 같다

hardware/libhardware/include/hardware/sensors.h

typedef struct sensors_event_t {
...
    heart_rate_event_t heart_rate
}sensors_event_t;

typedef struct {
    float bpm;
    int8_t status;
}heart_rate_event_t;

7. Build

모듈 빌드

source build/envsetup.sh
lunch odroidc2-eng-32
mmm hardware/hardkernel/libsensor

안드로이드 풀 빌드는 너무 오래 걸리기 때문에 일부 모듈만 빌드하는 mmm을 사용하도록 한다
참고 : http://www.kaisyu.com/notes/google-android/android-partial-module-build

결과

root@ubuntu: # mmm hardware/hardkernel/libsensor
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.1.1
TARGET_PRODUCT=odroidc2
...
target Strip: sensors.odroidc2 (out/target/product/odroidc2/obj/lib/sensors.odroidc2.so)
Install: out/target/product/odroidc2/system/lib/hw/sensors.odroidc2.so
make: Leaving directory

#### make completed successfully (1 seconds) ####

8. Install

백업

adb pull /system/lib/hw/sensors.odroidc2.so .

작업한 결과물이 이상할 수 있으므로 미리 백업한다

적용**

cp odroid/android/out/target/product/odroidc2/system/lib/hw/sensors.odroidc2.so /mnt/2/lib/hw/sensors.odroidc2.so

2번째 파티션에 파일을 교체한다


9. Reboot & Run

재부팅 하고 어플리케이션을 돌려본다
디버그 메세지들이 잘 뜨는지 확인


까먹고 안 썼는데 application 구현 참고

https://developer.android.com/reference/android/hardware/SensorManager.html

https://android.googlesource.com/platform/cts/+/ee43e0b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/HeartRateMonitorTestActivity.java


Posted by 쵸코케키

블로그 이미지
chocokeki
쵸코케키

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.5
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

최근에 올라온 글

최근에 달린 댓글

글 보관함