Skocz do zawartości

Przeszukaj forum

Pokazywanie wyników dla tagów 'ARM'.

  • Szukaj wg tagów

    Wpisz tagi, oddzielając przecinkami.
  • Szukaj wg autora

Typ zawartości


Kategorie forum

  • Elektronika i programowanie
    • Elektronika
    • Arduino i ESP
    • Mikrokontrolery
    • Raspberry Pi
    • Inne komputery jednopłytkowe
    • Układy programowalne
    • Programowanie
    • Zasilanie
  • Artykuły, projekty, DIY
    • Artykuły redakcji (blog)
    • Artykuły użytkowników
    • Projekty - DIY
    • Projekty - DIY roboty
    • Projekty - DIY (mini)
    • Projekty - DIY (początkujący)
    • Projekty - DIY w budowie (worklogi)
    • Wiadomości
  • Pozostałe
    • Oprogramowanie CAD
    • Druk 3D
    • Napędy
    • Mechanika
    • Wydarzenia
    • Sprzedam/Kupię/Zamienię/Praca
    • Inne
  • Ogólne
    • Ogłoszenia organizacyjne
    • Dyskusje o FORBOT.pl
    • Na luzie

Kategorie

  • Quizy o elektronice
  • Quizy do kursu elektroniki I
  • Quizy do kursu elektroniki II
  • Quizy do kursów Arduino
  • Quizy do kursu STM32L4
  • Quizy do pozostałych kursów

Szukaj wyników w...

Znajdź wyniki, które zawierają...


Data utworzenia

  • Rozpocznij

    Koniec


Ostatnia aktualizacja

  • Rozpocznij

    Koniec


Filtruj po ilości...

Data dołączenia

  • Rozpocznij

    Koniec


Grupa


Imię


Strona


TempX

Znaleziono 10 wyników

  1. Jak w temacie - oczywiście pod warunkiem, że program się w RAM'ie zmieści. Zdarza się, że uruchomienie programu w RAM jest bardzo wygodne. W moim przypadku mam external loadery, które zapisują flash SPI przy użyciu ST-LINK UTILITY, albo STM32CubeProgrammer. Problem z tymi aplikacjami jest taki, że o ile zapis do pamięci flash jest bezbłędny, o tyle odczyt czy weryfikacja nie przebiega poprawnie, chociaż dane w pamięci SPI flash zostały właściwie zapisane. Oprócz weryfikacji chciałbym mieć możliwość odczytywania do pliku danych zawartych w tych pamięciach flash i w tym momencie bardzo wygodnie jest wrzucić program do RAM, odczytać żądane dane swoim programem na VCP, nie naruszając programu głównego osadzonego we flaszu mikrokontrolera. Oczywiście wielka szkoda że firmowe programy tego nie uciągną i trzeba to rozwiązać we własnym zakresie. Odnalazłem 2 metody do linkowania programu w RAM. Pierwszą zastosowałem dla BLUEPILL'a PLUS (F103). Wystarczy podać linkerowi że początkowa część RAM jest pamięcią flash. MEMORY { RAM (xrw) : ORIGIN = 0x20002800, LENGTH = 10K FLASH (rx) : ORIGIN = 0x20000000, LENGTH = 10K } Druga rzecz, to dodanie 2 linii w startupie do zainicjalizowania stosu (SP) Reset_Handler: /* set stack pointer */ mov r0, 0x20000000 ldr sp, [r0] Trzecia rzecz, aby wszystko sprawnie działało z przerwaniami, to relokacja tablicy wektorów za pomocą rejestru SCB->VTOR SCB->VTOR = (uint32_t) 0x20000000; I... już - program działa, przerwania dla HAL_Delay(500) przychodzą od Systicka i wszystko pięknie śmiga. Pierwszy sposób, choć prosty, jest troszkę mniej poręczny od drugiego, w którym nie trzeba sztucznie dzielić pamięci RAM na FLASH i RAM. Drugi przykład wykonałem dla zestawu "Black board F407VE". Druga metoda jest dzięki uprzejmości MCD Application Team, który od pewnego czasu dla niektórych procesorów zaczął zamieszczać dwie wersje skryptu linkera, pierwszy z postfixem "FLASH", drugi z postfixem "RAM". Otóż wystarczy tylko w ustawieniach podmienić nazwę pliku linkera i na początku funkcji "main" zmienić adres tablicy wektorów jak w przypadku F103. Teraz jeszcze jedna rzecz - można by faktycznie binarki tych programów dołączać do programu we flaszu, który po resecie przepisywałby go do RAM, ale z drugiej strony... jaki sens ma umieszczenie programu z RAM we flash? Trochę dziwnie prawda? Chodzi mi o to, że takie programy z RAM zgodnie ze specyfikacją ARM'ów nie mają prawa uruchomić się, ponieważ proc startuje się z flasza!!! Co więcej, nawet gdyby zmieniono bootowanie na pamięć RAM, to nadal niewiele daje, ponieważ po odłączeniu zasilania w RAM przy starcie procka wartości są po prostu RANDOMOWE! I tutaj z pomocą przychodzi kolejny raz support STM32, który za pomocą programatora ST-link robi taką sztuczkę, że odczytuje adres startu programu (Entry Point) z tablicy wektorów i po zaprogramowaniu RAMu naszym programem na końcu rejestr PC zostaje zainicjowany adresem do Entry Pointa ! Prawda że genialne? W przypadku botowania ustawionego na flash program działa do pierwszego hardware'owego resetu. Nie sprawdzałem opcji, gdy bootowanie ustawione jest na RAM, ale według specyfikacji program powinien działać od nowa po hardware'owym resecie do momentu wyłączenia zasilania. W załączeniu programy: BLUEPILL_RAMRUN.zip , _F407_RAMRUN.zip Linki do repozytoriów na github: BLUEPILL PLUS RAM RUNNING STM32F407VET6 BLACK RUNNING IN RAM
  2. Z powodów sobie znanych mógłby ktoś chcieć uruchomić część kodu w RAM i nie jest to niemożliwe, a dzięki uprzejmości supportowi STM32 MCD Application Team zostało to zaimplementowane do prostego użycia. Programiści MCD Application Team dodali takie dwie ciekawe linie w sekcji ".data" skryptu linkera: *(.RamFunc) /* .RamFunc sections */ *(.RamFunc*) /* .RamFunc* sections */ To oznacza, że napisane funkcje z atrybutem (section(".RamFunc")) będą przez kompilator i linker traktowane jako dane do przepisania z flash'a do RAM. Sporządziłem mały programik dla BLUEPILL'a do blinkania diodą, żeby użyć tego ficzeru. Program jest bardzo mały, stworzony w STM32CubeIDE. W zasadzie składa się z 3 plików: 1. Rozbiegówki w assemblerze (to co się dzieje po resecie) 2. Pliku main.c w którym są zamieszczone 2 funkcje. Funkcja main(), oraz blink(). Funkcja blink jest funkcją przepisywaną do RAM. 3. Skryptu linkera. Wszystko jest okrojone do minimum, pousuwane zbędne includy, nieużywane opcje itd. Widok projektu: Funkcja blink (to uruchamiana w RAM) ma nadane 3 atrybuty: __attribute__ ((section(".RamFunc"), long_call, naked )) void blink(void) 1. Sekcji, wydzielającej ją do RAM 2. Atrybutu naked usuwającego zarządzanie stosem i zapisywaniem rejestrów (w tym konkretnym wypadku nie było to potrzebne) dla skrócenia programu 3. long_call pozwala skrócić wywoływanie procedury z RAM i zapobiega tworzeniu przez linker dodatkowej funkcji pośredniczącej w wywołaniu funkcji umieszczonej w RAM. Z podanych atrybutów obowiązkowy jest tylko pierwszy, pozostałe są użyte przeze mnie, ale nie są niezbędne do prawidłowego działania. Funcja blink() została napisana w assemblerze (raptem 11 linii) i robi dokładnie to, co 2 zakomentowane linie w C, oraz wykonuje powrót do miejsca wywołania z funkcji main() (bx lr). // GPIOB_ODR_REG ^= GPIOB_ODR_ODR2; // for(unsigned long int delay = 500000 ; delay != 0 ; delay--){} Na "rozbieg" po resecie wykonywany jest plik startupowy, również okrojony przeze mnie do niezbędnego minimum - oto jego zawartość: .syntax unified .cpu cortex-m3 .fpu softvfp .thumb .global g_pfnVectors .global .isr_vector .word _sidata .word _sdata .word _edata /******************************************************************************/ .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: /* Copy the data segment initializers from flash to SRAM */ ldr r0, =_sdata ldr r1, =_edata ldr r2, =_sidata movs r3, #0 CopyDataInit: ldr r4, [r2, r3] str r4, [r0, r3] adds r3, r3, #4 LoopCopyDataInit: adds r4, r0, r3 cmp r4, r1 bcc.n CopyDataInit /* Call the application's entry point.*/ b.n main .size Reset_Handler, .-Reset_Handler /******************************************************************************/ .section .isr_vector,"a",%progbits .type g_pfnVectors, %object .size g_pfnVectors, .-g_pfnVectors /******************************************************************************/ g_pfnVectors: .word _estack .word Reset_Handler /******************************************************************************/ Program z tego pliku przepisuje funkcę blink() z pamięci FLAH do RAM i następnie wykonuje skok do funkcji main() Funkcje main() i blink() nie są skomplikowane, a całość razem z definicjami i klamrami zamknęła się w około 40 liniach kodu... (...kodu?...) #define RCC_APB2ENR (*((unsigned long int *)0x40021018)) #define RCC_APB2ENR_IOPBEN (unsigned long int) 0x08 #define GPIOB_BASE (unsigned long int) 0x40010C00 #define GPIOB_CRL_REG (*((unsigned long int *) GPIOB_BASE)) #define GPIOB_CRL_VALUE (unsigned long int) 0x44484244 //#define GPIOB_ODR_REG (*((unsigned long int *) (GPIOB_BASE + 12))) //#define GPIOB_ODR_ODR2 (unsigned long int) 04 //----------------------- __attribute__ ((section(".RamFunc"), long_call, naked )) void blink(void) { // GPIOB_ODR_REG ^= GPIOB_ODR_ODR2; __asm ("ldr r0, gpiob_odr"); __asm ("ldr r1, [r0]"); __asm ("eor r1, #4"); __asm ("str r1, [r0]"); // for(unsigned long int delay = 500000 ; delay != 0 ; delay--){} __asm ("ldr r0, del_limit"); __asm ("calc: subs r0, #1"); __asm ("bne calc"); __asm ("bx lr"); __asm ("gpiob_odr: .word 0x40010C0C"); __asm ("del_limit: .word 500000"); } //---------------------- __attribute__ ((naked)) int main(void) { RCC_APB2ENR |= RCC_APB2ENR_IOPBEN; GPIOB_CRL_REG = GPIOB_CRL_VALUE; while (1) { blink(); } } Całość jest linkowana według skryptu konsolidatora, który również okroiłem do minimum. /* Entry Point */ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */ /* Memories definition */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K } /* Sections */ SECTIONS { /* The startup code into "FLASH" Rom type memory */ .isr_vector : { KEEP(*(.isr_vector)) /* Startup code */ } >FLASH /* The program code and other data into "FLASH" Rom type memory */ .text : { *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ _etext = .; /* define a global symbols at end of code */ } >FLASH /* Used by the startup to initialize data */ _sidata = LOADADDR(.data); /* Initialized data sections into "RAM" Ram type memory */ .data : { _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ *(.RamFunc) /* .RamFunc sections */ *(.RamFunc*) /* .RamFunc* sections */ _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH /* Uninitialized data section into "RAM" Ram type memory */ .bss : { /* This is used by the startup in order to initialize the .bss section */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON) _ebss = .; /* define a global symbol at bss end */ __bss_end__ = _ebss; } >RAM } Cały skompilowany oraz zdeassemblowany program to około 80 linii w assemblerze: Disassembly of section .text: 08000008 <main>: } //---------------------- __attribute__ ((naked)) int main(void) { RCC_APB2ENR |= RCC_APB2ENR_IOPBEN; 8000008: 4b05 ldr r3, [pc, #20] ; (8000020 <main+0x18>) 800000a: 681b ldr r3, [r3, #0] 800000c: 4a04 ldr r2, [pc, #16] ; (8000020 <main+0x18>) 800000e: f043 0308 orr.w r3, r3, #8 8000012: 6013 str r3, [r2, #0] GPIOB_CRL_REG = GPIOB_CRL_VALUE; 8000014: 4b03 ldr r3, [pc, #12] ; (8000024 <main+0x1c>) 8000016: 4a04 ldr r2, [pc, #16] ; (8000028 <main+0x20>) 8000018: 601a str r2, [r3, #0] while (1) { blink(); 800001a: 4b04 ldr r3, [pc, #16] ; (800002c <main+0x24>) 800001c: 4798 blx r3 800001e: e7fc b.n 800001a <main+0x12> 8000020: 40021018 .word 0x40021018 8000024: 40010c00 .word 0x40010c00 8000028: 44484244 .word 0x44484244 800002c: 20000001 .word 0x20000001 08000030 <Reset_Handler>: .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: /* Copy the data segment initializers from flash to SRAM */ 8000030: 4805 ldr r0, [pc, #20] ; (8000048 <LoopCopyDataInit+0xa>) ldr r0, =_sdata 8000032: 4906 ldr r1, [pc, #24] ; (800004c <LoopCopyDataInit+0xe>) ldr r1, =_edata 8000034: 4a06 ldr r2, [pc, #24] ; (8000050 <LoopCopyDataInit+0x12>) ldr r2, =_sidata 8000036: 2300 movs r3, #0 CopyDataInit: 8000038: 58d4 ldr r4, [r2, r3] 800003a: 50c4 str r4, [r0, r3] 800003c: 3304 adds r3, #4 800003e: 18c4 adds r4, r0, r3 8000040: 428c cmp r4, r1 8000042: d3f9 bcc.n 8000038 <CopyDataInit> /* Call the application's entry point.*/ 8000044: e7e0 b.n 8000008 <main> 8000046: 0000 .short 0x0000 8000048: 20000000 .word 0x20000000 _sdata 800004c: 2000001e .word 0x2000001e _edata 8000050: 08000054 .word 0x08000054 _sidata Disassembly of section .data: 20000000 <blink>: 20000000: f8df 0010 ldr.w r0, [pc, #16] ; 20000014 <gpiob_odr> "ldr r0, gpiob_odr" 20000004: 6801 ldr r1, [r0] 20000006: f081 0104 eor.w r1, r1, #4 2000000a: 6001 str r1, [r0, #0] 2000000c: 4802 ldr r0, [pc, #8] ; (20000018 <del_limit>) "ldr r0, del_limit" 2000000e <calc>: 2000000e: 3801 subs r0, #1 20000010: d1fd bne.n 2000000e <calc> 20000012: 4770 bx lr 20000014 <gpiob_odr>: 20000014: 40010c0c .word 0x40010c0c 20000018 <del_limit>: 20000018: 0007a120 .word 0x0007a120 } Gwoli ścisłości dodam, że program testuję na BlePillPLUS, który jest ulepszoną wersją pierwotnego BluePilla. Posiada 128KB wewnętrznej pamięci flash, jest lepiej zaprojektowane PCB i ma możliwość wlutowania szeregowej pamięci, do SPI1 procesora tj. PA5, PA6, PA7 z CS/ na PA4. Jest także drobna różnica, że LED nie jest jak w wersji poprzedniej na PC13, tylko jest zamontowane na PB2. Schemat płytki: Porównanie z poprzednią wersją: W załączniku omawiany program wyprodukowany w STM32CubeIDE BLUEPILL_BLINK.ZIP
  3. Witam, mam do sprzedania w pełni sprawny zestaw startowy Terasic DE0-Nano-SoC. Używałem go sporadycznie do nauki systemów wbudowanych i emulacji projektów w FPGA. Cena 300zł, sprzedaję razem z oryginalnym pudełkiem i dowodem zakupu ze sklepu Kamami. Odbiór osobisty w Gdańsku lub wysyłka kurierem.
  4. Cześć, mam pytanie o regulator PID z biblioteki dla procesorów ARM: arm_math.h. W bibliotece tej są 3 funkcje do obsługi regulatora: - arm_pid_f32(), - arm_pid_q31(), - arm_pid_q15(). 1. W jakich przypadkach powinno się używać której wersji? 2. Której wersji najlepiej użyć w przypadku potrzeby regulacji prądu generowanego przez PWM? Prąd jest regulowany poprzez ustawianie odpowiedniego wypełnienia sygnału PWM.
  5. Witam, Mam na imię Kamil, poszukuję pasjonatów chętnych do współpracy nad projektem systemu Internetu Rzeczy. Jak wiadomo rynek IOT błyskawicznie się rozwija. Do sieci podłączanych jest coraz więcej urządzeń. Rozwiązania tego typu znajdują coraz to szersze zastosowanie w najróżniejszych gałęziach przemysłu, gospodarki oraz na rynku konsumenckim. Moim celem jest zebranie zespołu pasjonatów w celu stworzenia polskiego rozwiązania systemu IOT. Temat jest bardzo rozległy oraz wymaga szerokiego zakresu wiedzy. Nie jestem w stanie zrealizować projektu samodzielnie, co sprawia, że zamieszczam ten wpis na wielu forach w nadziei, że znajdzie się grupa pasjonatów chętna do wspólnej pracy nad wykonaniem tego przedsięwzięcia. Pierwszym etapem projektu jest skompletowanie zespołu. Do współpracy poszukuję osób zajmujących się hobbystycznie: - Elektroniką oraz projektowaniem PCB, - Programowaniem mikrokontrolerów STM32, - Technologiami przesyłania danych, - Cyberbezpieczeństwem, - Technologiami Chmur obliczeniowych, - Bazami Danych, - Analizą danych, - Aplikacjami internetowymi oraz mobilnymi. Nie poszukuję Profesjonalistów lecz zapalonych Hobbystów, których motywuje ciągła chęć rozwoju oraz zgłębiania wiedzy. Wierzę, że uda nam się skomponować zespół Ludzi pełnych pasji, którzy wspólnymi siłami będą dążyć do osiągnięcia wyznaczonych sobie celów. Praca nad projektem będzie świetną okazją do wzajemnej wymiany wiedzy oraz doświadczenia. Uważam, że nieocenione są możliwości grupy Osób pełnych zaangażowania, które łączy wspólne hobby. Zdaję sobie sprawę, że cała koncepcja jest nieco szalona, aczkolwiek myślę, że warto spróbować. Kto wie co jesteśmy w stanie wspólnie osiągnąć :) . Osoby zainteresowane projektem w celu uzyskania informacji lub jakichkolwiek pytań proszone są o kontakt pod adresem e-mail: kamiliotsystem@gmail.com W tytule wiadomości proszę zamieścić swoje imię oraz obszar zainteresowań
  6. Cześć, po raz kolejny przychodzę z problemem. Mam płytkę STM32 NUCLEO F103RB, i ma ona złącza z arduino, a dokładnej dokumentacja mówi że jest to arduino uno. Tu nasuwa się moje pytanie, czy można taką płytkę programować jako arduino, pytam ponieważ już chwilę próbuję i nic nie udało mi się. Arduino ide podaje "Problem z wgrywaniem na płytkę". Starałem się to jakoś naprawić, jednak nie udało mi się. Czy jest w ogóle możliwe programowanie tego typu płytek jako arduino? Z góry dziękuję za odpowiedź!
  7. Sprzedam zestaw z płytką developerską Cy8ckit-062-ble Rev *B. Płytka używana kilka razy, ale jak nowa. W pełni sprawna. W zestawie płytka PSoC6, shield z wyświetlaczem, moduł BT do PC, kable połączeniowe i kabel USB-C. PSoC63 MCU: Dual-core MCU, with an Arm® Cortex®-M4 and Arm® Cortex®-M0+, 1MB of Flash, 288KB of SRAM, 78 GPIO, 7 programmable analog blocks, 56 programmable digital blocks, Bluetooth Low Energy (BLE), a serial memory interface, a PDM-PCM digital microphone interface, and industry-leading capacitive-sensing with CapSense™ Cena: 180 zł.
  8. Cześć. Zdarza mi się popełnić jakiś układ, który wykonuję samodzielnie - trawienie, lutowanie, programowanie itp. Hobbystycznie - dla siebie, ewentualnie coś dla znajomych. Zwykle korzystam z uC AVR, ale ostatnio bawię się płytkami Nucleo od STM. Powoli myślę o przesiadce z THT na SMT. I tu pojawia się pytanie - w jaki sposób programować takie mikrokontrolery? Mam w domu jakieś przejściówki z QFP na DIP, ale to wymaga przylutowania, zaprogramowania, odlutowania i przylutowania na gotowej płytce. Trochę mnie taki proces przeraża. Chciałem zakupić taki adapter z klipsem, ale okazuje się, że to uzależnia mnie zarówno od danej wielkości układu (QFP48, QPT64 itd.), jak i rozstawu nóżek (np. 0.8 mm dla AVR i 0.5 mm dla STM32). Znalazłem też takie igły-sondy z wysuwanymi szczypcami do chwytania nóżek, ale czy to mi chwyci 0.5 mm bez zwierania sąsiednich nóżek??? Czy jest jakieś w miarę uniwersalne rozwiązanie, które pozwoli mi na programowanie układów SMD o różnym rastrze, a przynajmniej różnej liczbie nóżek? Takie dedykowane adaptery są dość drogie (ok. 60 zł zwykły i ok. 300 zł z wyprowadzeniami JTAG/SWD i USART) i nie chciałbym kupować kilku, by móc używać różnych uC. Czy pozostaje mi wlutowywanie na docelowej płytce pinów do programowania? Używając SMD chciałbym przede wszystkim uniknąć wiercenia w płytce i zająć jak najmniej miejsca na niej, a takie piny trochę mi się z tym kłócą. Jakie rozwiązanie polecacie dla mnie? I drugie - poboczne pytanie: jak najlepiej/najłatwiej programować gołe scalaki z STM32, jeśli posiadam programatory z płytek Nucleo-64 i Nucleo-144?
  9. W zasilanym z baterii urządzeniu na STM32F103 mam kartę SD, i OLED. Po czasie bezczynności usypiam OLED i mikrokontroler. Niestety pobór prądu jest duży, ok 23mA. Zacząłem szukać przyczyny, okazało się, ze gdy wyjmę kartę SD, pobór prądu spada do 160uA. Po wyjęciu OLED pobór prądu spada do 60uA. Pomijając trochę za duży ale akceptowany pobór prądu przez mikrokontroler uśpieni lub jakiś element zewnętrzny duży problem mam z karta SD. Czasem zdarzy się, że nie pobiera dużo prądu (wszystko razem ok 1mA, z czego wynika, ze karta SD 840uA). Jak zmniejszyć pobór prądu przez kartę SD? Byłem przekonany, że gdy CS=H, to karta pobiera minimum energii (mam rezystor podciągający CS do zasilania) ale wygląda na to, że nie. Na wszelki wypadek odmontowuję kartę (nie sprawdziłem jeszcze, co tak naprawdę FatFS wtedy robi) ale to nic ni cdaje. Czy kartę trzeba uśpić jakąś komendą? Nic takiego nie znalazłem.
  10. Witam, dzisiaj przedstawię konstrukcję dość nietypową. Już temat brzmi zagadkowo co nie? "Blue pill" to nazwa taniej chińskiej płytki z mikro-kontrolerem STM32 F103. Kosztuje w Polsce ok 15 zł, za granicą chodzi po $2. Parametry w porównaniu do Arduino Uno na którym zwykłem wcześniej pracować są wręcz astronomiczne. Po chwili zabawy czujemy się jak po przesiadce z Malucha do Ferrari. Mamy na pokładzie kwarc 8MHz, którym według producenta możemy taktować płytkę do 72MHz. To jest oficjalna wartość, przy której producent gwarantuje nam że nasz mikro-kontroler będzie działać. Na własną odpowiedzialność natomiast można podkręcić ją sobie do 128MHz po prostu ustawiając mnożnik PLL-ki na najwyższą wartość. To jest na tyle proste że łatwo to przypadkiem zrobić 🙂 Reszta parametrów porównując do starej poczciwej atmegi to również niebo a ziemia. Mamy 20kB ramu i 64kB flasha, pełnoprawne USB i 12-bitowe ADC. Mamy też całą masę timerów. I to wszystko za góra 15 zł. Dobra, teraz drugie tajemnicze słowo. HVR to skrót od Hearth Rate Variability. Po polsku przebieg zmienności rytmu serca. Każdy z nas słyszał o tętnie. Serce bije z jakimś tam tempem, 60 BPM, 80 BPM itd. Przy wysiłku bije szybciej, w trakcie spoczynku wolniej. Jednak już znacznie mniej osób wie że odstępy między kolejnymi uderzeniami serca prawie nigdy nie są równe. I to nie mówię tu o małych różnicach. Zdecydowanie nie. Dobra, po prostu pokażę wam wykres. Na osi Y mamy puls w uderzeniach na minutę. Na osi X mamy kolejne uderzenia serca. Czerwona linia to dokładny wykres tętna, a żółty to wartość uśredniona. Robi wrażenie? Pulsometr pokazuje wam tylko wartość uśrednioną. Żółtą linię. Widzicie tętno 80, na prawdę jednak wasze serce skacze od 65 do 95. Dzieje się tak z każdym oddechem. Nie dokładnie, ale z moich obserwacji wynika że tętno względnie synchronizuje się z oddechem. Bynajmniej w stanie koherencji. Ha, teraz co to jest koherencja? O tym za chwilę. Co do samego urządzenia - jest to nasz ukochany Blue Pill z podpiętym czujnikiem MAX30100. Wszystko siedzi sobie na płytce stykowej. Płytkę można programować programatorem bądz przez UARTa. Co więcej jak byśmy zmienili bootloader to płytka może programować sie sama. Przez USB. Ja akurat wybrałem pierwszą opcję bo przypadkiem miałem pod ręką ST-Linka. Skąd miałem? Otórz dawno dawno temu zachwycony ARM-ami kupiłem sobie o taką płytkę. To było moje pierwsze spotkanie z ARM-ami. I wyglądało tak że spaliłem ją w ciągu jakiś 15 minut od podłączenia. Do tej pory nie wiem jak. Ale nie spaliłem pokładowego programatora który jak się okazuje bardzo chętnie przygarnia obce mikro-kontrolery. Więc naszego Blue Pilla za 15 zł można sobie podebugować nawet 🙂. Dużo ciekawiej wygląda program. Albowiem postanowiłem nie używać żadnej biblioteki. Nawet CMSIS-a. Tak więc mamy profesjonalną tablice wektorów w Asemblerze i jakże poważnie wyglądające definicje rejestrów. #define RCC_APB2ENR (*(volatile uint32_t *)(0x40021018)) czyż to nie jest piękne? Dobra, teraz na poważnie. Schemat działania programu jest dosyć prosty: Czekamy na przerwanie od czujnika Zczytujemy dane z czujnika Przepuszczamy je przez filtr DC ...i przez butterwortha żeby wyciąć wysokie częstotliwości Teraz mamy dość długi algorytm mający za zadanie wykryć puls. Jeśli właśnie wykryliśmy uderzenie serca (szczyt tej górki na dolnym obrazku), wyliczamy czas od poprzedniego i robimy z tego puls. Na koniec wysyłamy co trzeba UARTem (4 bajty) Jak działa czujnik? Czujnik składa się z diody IR i czujnika który ma za zadanie mierzyć natężenie światła z diody. Do czujnika przykładamy palec. Skóra bendzie w różnym stopniu przepuszczać światło, w zależności od chwilowego ciśnienia krwi. MAX30100 ma 16-bitowe ADC i konfigurowalną częstotliwość próbkowania. W moim projekcie używam 1000Hz. Niestety jak chcemy mieć dużo próbek to nie mamy pełnych 16 bitów 😞 . Po przefiltrowaniu mamy coś takiego: Dla jasności: screen jest stary, jak jeszcze nie był na 1kHz, stąd skala inna (wtedy było 50-100Hz, nie pamiętam już). A tak wygląda wykrywanie uderzeń serca: A teraz efekt końcowy. Spójrzcie na dwie sytuacje: Tak jak na początku mamy puls na osi Y i uderzenia na osi X. W pierwszej sytuacji robiłem pomiar w sytuacji stresowej. Wykres jest zupełnie chaotyczny. W drugiej mamy tzw. stan koherencji. Pomiar robiłem jakąś godzinę później, jak sytuacja stresowa minęła. Serce elegancko przyspiesza i zwalnia. Co więcej ze stanu pierwszego da się w ciągu paru minut świadomie przejść do stanu drugiego, po prostu przywołując pozytywne wspomnienia. Nie chcę tu za dużo opowiadać bo powoli wchodzimy w medycynę. A tutaj, bazując tylko na książkach mogę nie być najlepszym źródłem wiedzy. Software na komputerze: PlatformIO (po podaniu pliku linkera potrafi działać bez frameworka) SerialPlot - bardzo fajna maszyna do rysowania wykresów z tego co idzie po uarcie. Na koniec parę zdjęć konstrukcji:
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.