Linux Input Event Driver

주의

내공 부족으로 정확하지 않는 내용이 다수 있을 수 있음.
Subsystem이라고 부를 정도로 정말 거대하다.

0. The Input Subsystem

출처 : Essential Linux Device Drivers

hw -> Transfer Layer{spi, i2c, ….} -> input driver -> i2c core api -> input event driver -> Evdev Interface -> application

내가 코드 보며 이해한 바로는 이런데 실제로는 어떨련지 모르겠다.

굳이 input driver와 input event driver를 나누지 않고 하나로 합쳐서 작성된 것도 있다.


1. The Evdev Interface

include/linux/input.h
input subsystem의 자료형 및 정의가 있다

struct input_event {
  struct timeval    time;    //timestamp
  __u16                type;
  __u16                code;
  __s32                value;    //event value
}

이 구조체 형태로 /dev/input/ 디렉토리에 이벤트 값이 전달 된다.
주의 : 한 회에 한 종류 값만 전달 된다.

무슨 의미인고 하니 read로 읽을 때 이벤트 당 1개씩 값이 전달 된다는 이야기

예를 들어 (x, y) 좌표에 (12, 34) 클릭이 발생한 경우
data#1 - 클릭 발생
type = EV_KEY,
code = BTN_TOUCH,
value = 1

data#2 - x 좌표
type = EV_ABS,
code = ABS_X,
value = 12

data#3 - y 좌표
type = EV_ABS,
code = ABS_Y,
value = 34

data#4 - 이벤트 끝
type = EV_SYN, //event1 finished
code = SYN_REPORT,
value = 0

EV_SYN으로 하나의 이벤트 전송 종료를 알린다.

이벤트 리포팅을 위해

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value);
...
static inline void input_sync(struct input_dev *dev);

여러 이벤트 종류에 따라 각기 다양하게 함수들이 있다.


사용 예시
drivers/input/joystick/a3d.c

static void a3d_read(struct a3d *a3d, unsigned char *data)
{
  ...
  input_report_key(dev, BTN_RIGHT, data[2] & 1);
  input_report_key(dev, BTN_LEFT, data[3] & 2);
  ...
  input_report_abs(dev, ABS_X, ....);
  ...
  input_sync(dev);
}

data를 얻어와서 event 를 evdev로 보내는 모습

이 드라이버의 경우 data는 별도의 input driver에게 얻는다.

struct input_dev {
  ...
  struct input_id    id;
  unsigned long evbit[...];
  unsigned long keybit[...];
  ...
  int (*open)(struct input_dev *dev);
  void (*close)(struct input_dev *dev);
  ...
}

엄청나게 거대하므로 각각 역할은 커널소스의 주석을 직접 확인하기 바란다.


2. Example Source

drivers/input/keyboard/pxa27x_keypad.c

이 코드가 가장 보기 쉬웠어요

module_platform_driver
-> probe
-> request_mem_region, ioremap
-> input_allocate_device, input_dev 설정, request_irq
-> input_register_device

irq_handler - mmio read, input_event, input_report_key, input_sync
대략 이런 흐름인 것 같다.


3. Linux input event read Application code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/time.h>
#include <string.h>

int main()
{
    int fd, ret;
    int x, y;
    const char* evdPath = "/dev/input/event3";
    struct input_event iev[3];

    fd = open(evdPath, O_RDONLY);

    if(fd < 0) {
        perror("error");
        return -1;
    }

    while(1) {
        ret = read(fd, iev, sizeof(struct input_event)*3);
        if(ret < 0) {
            perror("error");
            break;
        }

        if(iev[0].type == EV_REL && iev[0].code == REL_X)
            x = iev[0].value;
        if(idev[1].type == EV_REL && iev[1].code == REL_Y)
            y = iev[1].value;

        printf("x:%d, y:%d\n", x, y);
        printf("%hu, %hu, %d\n", iev[0].type, iev[0].code, iev[0].value);
        printf("%hu, %hu, %d\n", iev[1].type, iev[1].code, iev[1].value);
        printf("%hu, %hu, %d\n", iev[2].type, iev[2].code, iev[2].value);
    }

    close(fd);
    return 0;
}

RUN

4, 3
2, 0, 4
2, 1, 3
0, 0, 0
...

별 설명할 꺼리가 없다……
다만 왜 event3로 생성이 되는지 그건 잘 모르겠다.


4. virtual input event driver code

이름은 거창한데 사실 별거 없다
hw 에서 인터럽트 혹은 데이터를 안 받았는데 그냥 데이터 들어왔다고 evdev에게 이벤트를 알리는 것이다.

const char                 *pdev_name = "ietest";
struct platform_device    *pdev;
struct ev_test {
      struct input_dev    *input_dev;
      struct task_struct    *task;
};

int read_data_from_sensor(void)
{
  static int roll = 0;
  return roll++%2 ? 3 : 4;
}

void set_input_device_property(struct input_dev *dev)
{
  set_bit(EV_REL, dev->evbit);
  set_bit(REL_X, dev->relbit);
  set_bit(REL_Y, dev->relbit);
}

void send_event_msg_to_evdev(struct input_dev *dev)
{
  input_report_rel(dev, REL_X, read_data_from_sensor());
  input_report_rel(dev, REL_Y, read_data_from_sensor());
  input_sync(dev);
}

static int hw_fake_int_handler(void *arg)
{
  struct ev_test *event_ctrl = (struct ev_test*) arg;
  struct input_dev *idev = event_ctrl->input_dev;

  while(!kthread_sould_stop())        //check stop signal
  {
    send_event_msg_to_evdev(idev);
    msleep_interruptible(300);
  }

  return 0;
}

/* REMOVED ERROR CHECKING ROUTINE */
static int inputevent_test_init(void)
{
  int ret;
  struct ev_test        *event_ctrl;
  struct task_struct    *task;
  struct input_dev        *idev;

  /* platform or i2c or spi or serio or etc ... */
  pdev = platform_device_register_simple(pdev_name, -1, NULL, 0);

  event_ctrl = kzalloc((sizeof(struct ev_test)), GFP_KERNEL);

  idev = input_allocate_device();
  set_input_device_property(idev);
  input_register_device(idev);

  task = kthread_run(hw_fake_int_handler, event_ctrl, 
                          "ieint_%s_#%d", pdev_name, 1);

  event_ctrl->input_dev = idev;
  event_ctrl->task = task;
  dev_set_drvdata(&pdev->dev, event_ctrl);

  return 0;
}

static void inputevent_test_exit(void)
{
  struct ev_test    *event_ctrl = (struct ev_test*)dev_get_drvdata(&pdev->dev);
  kthread_stop(event_ctrl->task);

  input_unregister_device(pdev);  
}

module_init(inputevent_test_init);
module_exit(inputevent_test_exit);

이 코드에서는 pdev를 가상으로 만들었지만 실제로는 여러 통신 방식을 통해 probe 되고 거기에 interrupt handler를 등록해서 input event 를 보내는 식으로 처리하는 것 같다
인터럽트 핸들러 대신 가상으로 커널 쓰레드를 만들어서 계속 좌표를 보내도록 개발했다


기타 github에 올려본 예제

https://github.com/chocokeki/input_event_driver

Posted by 쵸코케키

병렬처리 할 때 편하단다

그래서 써보려고 ㅎㅎ


https://golang.org/


https://go-tour-kr.appspot.com


http://knight76.tistory.com/entry/Go-lang-workspace-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

'devel > 개념' 카테고리의 다른 글

Linux Kernel DMA  (0) 2017.03.02
Linux Input Event Driver  (0) 2017.02.23
gpio pull down switch 연결  (0) 2016.11.16
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
Posted by 쵸코케키








+-----+  +-----------+  +------+  +--------+  +------+

| LED +--+ resistor  +--+ gpio +--+ switch +--+ 3.3V |

+--+--+  +----+------+  +------+  +--------+  +------+

   |          |

+--+--+    +--+--+

| GND |    | GND |

+-----+    +-----+





'devel > 개념' 카테고리의 다른 글

Linux Input Event Driver  (0) 2017.02.23
golang 고랭지 농업이 아니라 go 언어  (0) 2016.12.01
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
Posted by 쵸코케키




BarrSlides_FINAL_SCRUBBED.pdf

모든 저작권은 BARR group에게 있음

'devel > 개념' 카테고리의 다른 글

golang 고랭지 농업이 아니라 go 언어  (0) 2016.12.01
gpio pull down switch 연결  (0) 2016.11.16
mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
Posted by 쵸코케키

mmap 구현 방식 2가지

ldd 많이 참조함, 옅은 지식으로 쓴 내용이라 틀릴 수 있음

mmap의 역할?

kernel 공간 혹은 하드웨어 장치에 있는 메모리를 복사하는 과정 없이 user 공간에게 제공
rw가 엄청나게 발생하는 경우에 꽤나 의미있는 성능향상을 보여줄 수 있다
c 어플리케이션에서 mmap 함수를 호출하면 device driver의 mmap 함수가 호출된다
그 함수를 구현하는게 목표


어플리케이션 영역

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
          int fd, off_t offset);
int munmap(void *addr, size_t length);

자세한 설명은 man 페이지 참조
flag는 계속 늘어나는데 MAP_HUGETLB 같이 huge page를 쓸 때 필요한 옵션도 있다
그냥 일반적인 flag로는 MAP_SHARED(다른 프로세스랑 같이 공유) 가 있겠다
prot는 page의 권한에 관한 내용이다
페이지가 읽힐 예정인지 쓰거나 실행될련지 등등


mmap 구현

요약 : 아래의 함수들을 잘 조합해서 사용하면 된다

io_remap_pfn_range()
remap_pfn_range()

아니면 fault 를 처리하는 방식으로 구현해도 ok

vm_insert_page()
vm_insert_pfn()

fault 처리에 주로 사용된다

원형

include/linux/fs.h
struct file_operation {
    ...
    int (*mmap) (struct file *, struct vm_area_struct *);
}

remap_pfn_range 사용

remap_pfn_range - remap kernel memory to userspace
system RAM을 맵핑하고 싶을 때 사용
참고 : io_remap_pfn_range은 장치의 I/O memory 즉 phys_addr_t로 표현되는 놈을 매핑하고 싶을 때 사용
nommu가 아닌이상 동일

내가 파악한 바로는(틀릴 수 있지만 ㅠㅜ)

  1. 유저에서 mmap을 호출하면 (사용할 수 있는 커널 메모리 쫌만 주세요. 대신 제가 알아볼 수 있는 주소로요)
  2. 위의 요청 정보가 vma 형태로 driver로 들어오고(메모리 정보)
  3. 인제 개발자는 가지고 있던(미리 할당해두었던) 메로리를 vma랑 붙여주는데
  4. 그 때 사용하는 도구가 remap_pfn_range 인가보다

이 함수는 userspace의 addr ~ addr+size 범위의 virtual address를 위한 page table을 만든다
이 함수는 pfn<<PAGE_SHIFT ~ (pfn<<PAGE_SHIFT) + size 까지 해당하는 물리 메모리 영역에 영향을 준다

include/linux/pfn.h
#define PFN_PHYS(x)     ((phys_addr_t)(x) << PAGE_SHIFT)
#define PHYS_PFN(x)     ((unsigned long)((x) >> PAGE_SHIFT))

int remap_pfn_range(struct vm_area_struct *vma,  
                    unsigned long addr, 
                    unsigned long pfn,
                    unsigned long size, 
                    pgprot_t prot)

vma : 매핑될 virtual memory area - 변태가 아닌 이상 mmap 호출될 때 vma 인자가 같이 딸려오므로 그대로 쓰면 된다. 하지만 변태라면?!
addr : target user address to start at
pfn : page frame number of kernel memory
보통 physical address >> PAGE_SHIFT 한 값이다
이 physical address에 addr(target user address, virtual address)가 매핑되게 된다

size : 바이트 단위의 매핑될 영역 크기. 보통 vma->vm_end - vma->vm_start
prot : page protection flag, 보통 vma->vm_page_prot 값을 사용한다

이 함수를 호출할 때 흔히 다음과 같이 한다(아래 참조)

예시 : drivers/uio/uio.c

static const struct file_operations uio_fops = {
    ...
    .mmap = uio_mmap,
}

static int uio_map(struct file *filep, struct vm_area_struct *vma)
{
    ...
    return uio_mmap_physical(vma);
}

static int uio_mmap_physical(struct vm_area_struct *vma)
{
    ...
    return remap_pfn_range(vma,
                           vma->vm_start,
                           mem->addr >> PAGE_SHIFT,    //미리 할당해두었던 메모리 
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);
}

조금 형태가 다르긴 한데 이런 것도 있다
drivers/vfio/pci/vfio_pci.c

static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
{
    ...


    pgoff = vma->vm_pgoff &
            ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);    //???

    u64 phys_len = pci_resource_len(pdev, index);    
    req_start = pgoff << PAGE_SHIFT;
    req_len = vma->vm_end - vma->vm_start;

    if(phys_len < PAGE_SIZE || req_start + req_len > phys_len)    //크기 검사
        return -EINVAL;

    vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;

    return remap_pfn_range(vma, vma->start, vma->vm_pgoff,
                            req_len, vma->vm_page_prot);
    //어차피 remap_pfn_range를 호출하면 vma->vm_pgoff = pfn 이 된다
}

아니면 이런 애들도 있다
sound/core/pcm_native.c

int snd_pcm_lib_default_mmap(...)
{
    area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
#ifdef CONFIG_GENERIC_ALLOCATOR
    if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
            area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
            return remap_pfn_range(area, area->vm_start,
                            substream->dma_buffer.addr >> PAGE_SHIFT,
                            area->vm_end - area->vm_start, area->vm_page_prot);
    }    
#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
    if (!substream->ops->page &&
        substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
            return dma_mmap_coherent(substream->dma_buffer.dev.dev,
                                     area,
                                     substream->runtime->dma_area,
                                     substream->runtime->dma_addr,
                                     area->vm_end - area->vm_start);
#endif /* CONFIG_X86 */
    /* mmap with fault handler */
    area->vm_ops = &snd_pcm_vm_ops_data_fault;
    return 0;
}

기타 다른 예시
drivers/infiniband/hw/nes/nes_verbs.c

static int nes_mmap(struct ...)
{
    ...
    remap_pfn_range( ...
    virt_to_phys >> PAGE_SHIFT ...)
    ...
}

.pgprot

잘 몰라서 생략
대략 cache 쓸껀지 말껀지 관한 내용인데
pgprot_noncached, pgprot_writecombine, pgprot_writethrough
등이 있다


기타

drivers/media/platform/omap/omap_vout.c
OMAP 24xx camera controller 코드

처음 매몰이 할당 코드

virt_addr = omap_vout_alloc_buffer(vout->buffer_size, &phy_addr);
vout->buf_virt_addr[i] = virt_addr;
vout->buf_phy_addr[i] = phy_addr;

unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
{
    u32 order, size;
    unsigned long virt_addr, addr;

    size = PAGE_ALIGN(buf_size);    //참고로 가로px * 세로px * bpp(bits per pixel)
    order = get_order(size);
    virt_addr = __get_free_pages(GFP_KERNEL, order);
    addr = virt_addr;

    *phys_addr = (u32) virt_to_phys((void *) virt_addr);
    return virt_addr;
}

mmap 코드

vm_operations_struct omap_vout_vm_ops
    .open = vout->mmap_count++; 역할 수행(mmap )
    .close =  vout->mmap_count--; 역할 수행

mmap 호출한다고 해서 mmap open까지 같이 호출되지는 않는다
놀랍게도 r/w 둘 다 open을 호출하지 않는다
open은 process가 fork할 때 불려진다
그리고 vma에 대한 새로운 reference를 생성한다

static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
{
    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - vm->vm_start;
    ...
    void* pos = (void *)vout->buf_virt_addr[i];            //kernel logical address(virtual address)
    vma->vm_pgoff = virt_to_phys((void *) pos) >> PAGE_SHIFT;    //physical
    vma->vm_ops = &omap_vout_vm_ops;
    ...

    while(size > 0) {
        unsigned long pfn;
        pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;        //물리 주소 획득
        if(remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
            return -EAGAIN;
        start += PAGE_SIZE;
        pos += PAGE_SIZE;
        size -= PAGE_SIZE;
    }

    vout->mmap_count++;        
}

remap_pfn_range에 size를 한 번에 넣는게 아니라 PAGE_SIZE로 나눠 하는 이유?
pixel size가 크다고 해도 어차피 kmalloc 한계인 MAX_ORDER(2^ 10 ~11, 1024) * PAGE_SIZE(4096B) = 4MB or 8MB 이내 범위로 메모리가 할당되어 있다
왜 이짓을 하냐면 메모리가 cma같은게 아닌이상 크게 할당이 안되고 PAGE_SIZE 크기로 할당해서 일듯?
vma 유저 메몰희랑 pfn 물리 매몰의랑

추가 참고 : http://www.cs.fsu.edu/~baker/devices/notes/ch15.html#(34)

그 외 fault 직접 관리

vm_opeartions_struct 의 fault 함수를 직접 구현해야 함
결론적으로 vmf->page = page 를 해주어 메모리를 제공하면 끝
제공해줄 page는 어디서 얻냐고?
여러가지 구현 방법이 있는데 get_zeroed_page 같은 함수로 미리 얻어놓거나
필요할 때마다 획득하거나 등등

예시 : sound/usb/usx2y/usX2Yhwdep.c, sound/core/memalloc.c
mmap이 호출되면 __get_free_pages 로 shared memory 호출하고
fault가 호출되면 아래의 함수가 호출된다

static int snd_us428ctls_vm_fault(struct vm_area_struct *area, 
                                  struct vm_fault *vmf)
{
    ...
    offset = vmf->pgoff << PAGE_SHIFT;        //physical to kernel logical
    vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset;    
    //미리 얻어놨던 메모리 조금씩 제공
    page = virt_to_page(vaddr);
    vmf->page = page;
    get_page(page);                // 나 이 페이지 쓴다!
}

혹은 다른 예시 - dma 같은게 필요 없는 경우
drivers/uio/uio.c

static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    page = vmalloc_to_page(addr);
    get_page(page);
    vmf->page = page;
}

drivers/staging/android/ion/ion.c

static int ion_vm_fault(staruct vm_area_struct *vma, struct vm_fault *vmf)
{
    ...
    vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
    ...
}

그 외 dma common mmap

include/linux/dma-mapping.h

struct dma_map_ops {
    ...
    int (*mmap)(struct device *, struct vm_area_struct *,
                    void *, dma_addr_t, size_t, struct dma_attrs *attrs);
}

drivers/base/dma-mapping.c 참고
int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
        int ret = -ENXIO;
#if defined(CONFIG_MMU) && !defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP)
        unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
        unsigned long off = vma->vm_pgoff;

        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                            include/linux/mm.h 

        if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;

        if (off < count && user_count <= (count - off)) {
                ret = remap_pfn_range(vma, vma->vm_start,
                                      pfn + off,
                                      user_count << PAGE_SHIFT,
                                      vma->vm_page_prot);
        }   
#endif  /* CONFIG_MMU && !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */

        return ret;
}

http://anster.egloos.com/m/2141358ㅁ

'devel > 개념' 카테고리의 다른 글

gpio pull down switch 연결  (0) 2016.11.16
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
Posted by 쵸코케키

2016. 8. 10. 13:43 devel/개념

stm32f4 절전모드

STM32F4xx 시리즈의 sleep, stop mode에 대해



STM32F4xx block diagram


 stm32f41x_block_diagram

시리즈 마다 다르겠지만 대충 이런 식으로 생겼다

일단은 넘어가자




#Sleep Mode

Sleep Mode는 아래 함수로 쉽게 진입이 가능한데

HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

Wakeup 조건이 모든 인터럽트기 때문에 sleep으로 들어가기 전에 SysTick 관련 interrupt도 꺼야 한다

안 그러면 잠자리에 눕자마자 일어나는 불상사가......

SysTick 때문에 바로 깨어날 경우 아래와 같이 Tick을 잠시 중단 시키면 된다

 

HAL_SuspendTick();

HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

HAL_ResumeTick();

 

1번 인자로 PWR_MAINREGULATOR_ON를 이용해도 좋다 그런데 MR이 뭔지 모르겠다

2번째 인자로 PWR_SLEEPENTRY_WFE를 사용해도 된다

여기서 Event가 뭐인고 하니 EXTIexception 등등

자세한 내용은 D022708, 48p Wakeup from WFE 를 참고 바란다

 

 

# 1.2v domain - DM00127514, 112p

core, memory, digital peripherals

 

# STOP MODE - DM00127514, 113p, 120p

1.2v domain, PLLs, HSI, HSE RC oscillator disabled

Internal SRAM, register contents are preserved

SRAM 내용 유지(SRAM에 관한 상세 내용은 아래에), 레지스터 내용 유지

그리고 각종 oscillator domain 관련은 block diagram을 확인 하여 영향도를 체크하자

 

# HSI, HSE - DM00127514, 135p

상세 내역은 pdf 참조

일단은 AHB에 연결된 아해들이 정상 동작 않겠구나 생각해두자

 

그건 그렇고 stop mode에도 2가지 모드가 있다

이하 STOP MODE 해석 안 하는 게 더 나을 꺼 같아서 생략

 

Normal mode

the 1.2 V domain is preserved in nominal leakage mode.

It is the default mode when the main regulator (MR) or the low-power regulator (LPR) is enabled.

- HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

 

Under drive mode

the 1.2 V domain is preserved in reduced leakage mode.

This mode is only available when the main regulator or the lowpower regulator is in low voltage mode

- HAL_PWREx_EnterUnderDriveSTOPMode(PWR_LOWPOWERREGULATOR_UNDERDRIVE_ON, PWR_SLEEPENTRY_WFI);

 

Under drive mode가 전기 더 덜 먹는다는 이야기

대신 wakeup time이 더 소모 된다.

          

 

#SRAM?

2.3.1 Embedded SRAM, 68p, 71p 참조

MCU 내부에 있는 램. 용량 매우 작다

linker script 작성에 따라서 다르긴 하지만 external RAM 없다는 가정하에

일반적으로 흔히 우리가 생각하는 heap stack이 살아 숨쉬는 RAM이라고 보면 된다

 

STOP mode에서 Under drive Mode 로 진입하면 더욱 저전력 가능

대신 wakeup time이 더 소모

wakeup time의 딜레이를 사용자가 줘야 하는 게 아니라 그냥 좀 더 걸린다 정도로 이해하면 될 듯

그래도 머 ns 단위로 전부 깨어나지 않을까

각각 딜레이 보면 < Xns 이런 식으로 되어있고 정확한 값은 없음

아래 Table 20. Stop operating modes 참고



'devel > 개념' 카테고리의 다른 글

도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
Posted by 쵸코케키


https://lwn.net/Articles/619514/


A compound page is simply a grouping of two or more physically contiguous pages into a unit that can, in many ways, be treated as a single, larger page. They are most commonly used to create huge pages, used within hugetlbfs or thetransparent huge pages subsystem



'devel > 개념' 카테고리의 다른 글

mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
ld linker script 예시  (0) 2016.07.25
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
64bit linux kernel memory layout  (1) 2016.05.31
Posted by 쵸코케키

출처

http://www.hertaville.com/a-sample-linker-script.html




/******************************************************************************
    * This linker file was developed by Hussam Al-Hertani. Please use freely as
    * long as you leave this header in place. The author is not responsible for any
    * damage or liability that this file might cause.
******************************************************************************/

   /* Entry Point */
   ENTRY(Reset_Handler)

   /* Specify the memory areas */
   MEMORY
   {
     FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 0x10000 /*64K*/
     RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 0x02000 /*8K*/
   }

   /* define stack size and heap size here */
   stack_size = 1024;
   heap_size = 256;

   /* define beginning and ending of stack */
   _stack_start = ORIGIN(RAM)+LENGTH(RAM);
   _stack_end = _stack_start - stack_size;

   /* 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) */
       *(.text*)          /* .text* sections (code) */
       *(.rodata)         /* .rodata sections (constants, strings, etc.) */
       *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
       *(.glue_7)         /* glue arm to thumb code */
       *(.glue_7t)        /* glue thumb to arm code */
       . = ALIGN(4);
       _etext = .;        /* define a global symbols at end of code */
     } >FLASH

      .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
       .ARM : {
       __exidx_start = .;
         *(.ARM.exidx*)
         __exidx_end = .;
       } >FLASH

     /* used by the startup to initialize data */
     _sidata = .;

     /* Initialized data sections goes into RAM, load LMA copy after code */
     .data : AT ( _sidata )
     {
       . = ALIGN(4);
       _sdata = .;        /* create a global symbol at data start */
       *(.data)           /* .data sections */
       *(.data*)          /* .data* sections */

       . = ALIGN(4);
       _edata = .;        /* define a global symbol at data end */
     } >RAM

     /* Uninitialized data section */
     . = ALIGN(4);
     .bss :
     {
       /*  Used by the startup in order to initialize the .bss secion */
       _sbss = .;         /* define a global symbol at bss start */
       __bss_start__ = _sbss;
       *(.bss)
       *(.bss*)
       *(COMMON)

       . = ALIGN(4);
       _ebss = .;         /* define a global symbol at bss end */
       __bss_end__ = _ebss;
     } >RAM

       . = ALIGN(4);
       .heap :
       {
           _heap_start = .;
           . = . + heap_size;
                   _heap_end = .;
       } > RAM

       /* Remove information from the standard libraries */
       /DISCARD/ :
       {
           libc.a ( * )
           libm.a ( * )
           libgcc.a ( * )
       }

       .ARM.attributes 0 : { *(.ARM.attributes) }
   }


'devel > 개념' 카테고리의 다른 글

stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
64bit linux kernel memory layout  (1) 2016.05.31
헤더파일 전역변수 중복 오류  (0) 2016.04.21
Posted by 쵸코케키

http://www.edwardbosworth.com/My5155Textbook/MyText5155_AFrontMatter.htm


강추

'devel > 개념' 카테고리의 다른 글

__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
64bit linux kernel memory layout  (1) 2016.05.31
헤더파일 전역변수 중복 오류  (0) 2016.04.21
EAS(Energy-Aware Scheduler) 스케쥴러 정리  (0) 2016.03.24
Posted by 쵸코케키

64비트 리눅스 커널메모리 맵

Documentation/x86/x86_64/mm.txt


AMD64 canonical address form 이라고도 하는듯


상위 - 커널이 사용(40bit?)

하위 - 유저스페이스(47bit)

나머지 - hypervisor용 등등 그냥 비워둠


하지만 kmalloc 제한은 엄청 작다

신형 대용량 메모리 할당 기법들을 사용해야 한다



기타 64bit low memory 관련 글

http://www.criticalworld.co.kr/?p=56

Posted by 쵸코케키
이전버튼 1 2 3 이전버튼

블로그 이미지
chocokeki
쵸코케키

공지사항

Yesterday
Today
Total

달력

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

최근에 올라온 글

최근에 달린 댓글

글 보관함