제퍼에서 thread를 굳이 나누자면
System thread와
User thread로 나눌 수 있어.
System thread는 main()을 호출하는 main thread와 idle thread 그리고 workqueue thread 정도가 될거고
User thread는 말 그대로 유저가 만드는 거겠지.
Thread 뭐 별거 없어.
생성하고 종료하고 멈추고 재시작하고 이게 전부.
이왕 이면 예제를 통해 살펴보는게 좋겠지?
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_thread my_thread_data;
k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
K_THREAD_STACK_SIZEOF(my_stack_area),
my_entry_point,
NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
이건 제퍼 공식 문서에서 제공하는 예제야.
k_thread_create라는 함수를 이용해서 MY_STACK_SIZE 크기의 메모리를 갖는 thread를 생성하는거지.
그런데 이렇게 하려면 main()안에서 k_thread_create를 호출해야 해.
runtime 전용인거지
👇👇👇
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
#define LED0_NODE DT_NODELABEL(led0)
#define LED1_NODE DT_NODELABEL(led1)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);
static struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE,gpios);
void my_entry_point(void *, void *, void *){
int ret;
ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
for(;;){
gpio_pin_toggle_dt(&led1);
k_sleep(K_MSEC(500));
}
}
K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_thread my_thread_data;
void main(void)
{
int ret;
ret = gpio_pin_configure_dt(&led0,GPIO_OUTPUT);
k_tid_t my_tid = k_thread_create(&my_thread_data, my_stack_area,
K_THREAD_STACK_SIZEOF(my_stack_area),
my_entry_point,
NULL, NULL, NULL,
MY_PRIORITY, 0, K_NO_WAIT);
for(;;){
gpio_pin_toggle_dt(&led0);
k_sleep(K_MSEC(1000));
}
}
뭐 이것도 나쁘지 않지만 사실 더 편한 방법이 있어.
런타임이 아니고 컴파일 타임에 thread를 생성할 수 있는 메크로가 제공되거든.
아래는 제퍼 공식 문서 예제
👇👇
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
extern void my_entry_point(void *, void *, void *);
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
MY_PRIORITY, 0, 0);
훨씬 간단하지?
이렇게 하면 main()에서 호출할 필요없이 thread가 생성돼.
👇👇
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
#define LED0_NODE DT_NODELABEL(led0)
#define LED1_NODE DT_NODELABEL(led1)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);
static struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE,gpios);
void my_entry_point(void *, void *, void *){
int ret;
ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
for(;;){
gpio_pin_toggle_dt(&led1);
k_sleep(K_MSEC(300));
}
}
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
MY_PRIORITY, 0, 0);
void main(void)
{
int ret;
ret = gpio_pin_configure_dt(&led0,GPIO_OUTPUT);
for(;;){
gpio_pin_toggle_dt(&led0);
k_sleep(K_MSEC(1000));
}
}
처음에 설명했듯이 여기에서 main()을 삭제해도 새로 만든 thread는 동작해.
main()은 그냥 main thread에서 초기화를 마친 후 호출하는 함수에 불과하기 때문.
궁금한 사람들은 한번 해보자.
thread를 아예 종료(abort)하는 일은 드물것 같으니 넘어가고 대신
suspend - resume을 해보자고
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#define MY_STACK_SIZE 500
#define MY_PRIORITY 5
#define LED0_NODE DT_NODELABEL(led0)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE,gpios);
void my_entry_point(void *, void *, void *){
int ret;
ret = gpio_pin_configure_dt(&led1,GPIO_OUTPUT);
for(;;){
gpio_pin_toggle_dt(&led1);
k_sleep(K_MSEC(50));
}
}
K_THREAD_DEFINE(my_tid, MY_STACK_SIZE,
my_entry_point, NULL, NULL, NULL,
MY_PRIORITY, 0, 0);
void main(void)
{
for(;;){
k_thread_suspend(my_tid);
k_sleep(K_MSEC(1000));
k_thread_resume(my_tid);
k_sleep(K_MSEC(1000));
}
}
역시나... 너무 쉽게.. 동작..
딱히 더 할게 생각나지 않는다;;;
아래는 제퍼 thread 상태를 다이어그램으로 나타낸거야.
어떤 상태가 있는지 정도는 알아두자. 그럼 안녕!
👉👉 nrf 보드가 52840DK가 아니라 5340DK인데 너무 신경쓰지 말자. 동작은 똑같아 ㅎ
2023.06.02 - [임베디드 소프트웨어/Zephyr] - [nRF52840 + Zephyr] #9. Memory Management
'임베디드 소프트웨어 > Zephyr' 카테고리의 다른 글
[nRF52840 + Zephyr] #10. Time management (0) | 2023.06.03 |
---|---|
[nRF52840 + Zephyr] #9. Memory Management (0) | 2023.06.02 |
[nRF52840 + Zephyr] #7. RTOS 기본 (0) | 2023.05.24 |
[nRF52840 + Zephyr] #6. KConfig (0) | 2023.05.22 |
[nRF52840 + Zephyr] #5. 디바이스 트리 3 (0) | 2023.05.12 |