Przeszukaj forum
Pokazywanie wyników dla tagów 'SPI'.
Znaleziono 10 wyników
-
Cześć wszystkim. Chciałbym skonfigurować akcelerometr mc3479 do pomiaru położenia komunikując się z czujnikiem przy użyciu interfejsu spi. Do tej pory nie wykorzystywałem zbyt tego interfejsu i mam problem z funkcjami do zapisu oraz do odczytu rejestrów. Mianowicie po napisaniu funkcji nie jestem w stanie zapisać/odczytać wartości z czujnika. Próbowałem podać przykładową wartość, ale niestety nie zadziałało. Czy ktoś ma pomysł co mogłem przeoczyć? 🙂 void mc_reg_write(uint8_t reg, uint8_t value) { uint8_t tx[3] = { 0x40 | reg, value, 0x00 }; HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, tx, 3, HAL_MAX_DELAY); HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_SET); } uint8_t mc_reg_read(uint8_t reg) { uint8_t tx_data[2] = { reg | 0x80, 0x00 }; uint8_t rx_data[2] = { 0x00, 0x00 }; HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 2, HAL_MAX_DELAY); HAL_GPIO_WritePin(CSACC_GPIO_Port, CSACC_Pin, GPIO_PIN_SET); return rx_data[1]; } mc_reg_write(0x12, 0x01); printf("In register 0x%02X is: (0x%02X)\r\n",0x12, mc_reg_read(0x12));
-
Witam wszystkich, bez zbędnych szczegółów mam do zrobienia układ który będzie musiał: Obsługa Xbee za pomocą magistrali UART Obsługa przetwornika A/C C/A (wstępnie myślałem nad układem pod magistralę I2C) Obsługa wyświetlacza OLED (również myślałem nad magistralą I2C ze względu na to że posiadam już takowy) Obsługa wyświetlacza LCD (chyba po magistrali SPI ok 3 cali) podgląd z kamery poprzez WiFi Obsługa WiFi jak w punkcie powyżej. Posiadać USB do kontrolera Ze względu na studencki budżet udało mi się kupić w bardzo dobrych pieniądzach (jak na obecną sytuację z "malinami") a są to Raspberry Pi zero wersje 1.3 oraz 1.1. Obawiam się, że jedna malinka nie podoła. Myślałem nad połączeniem dwóch za pomocą magistrali I2C ale wyczytałem, że Rasberry Pi może pracować tylko jako urządzenie typu Master i teraz nie wiem czy jedna dałaby rade podołać wszystkiemu czy dałoby radę jednak jakoś mądrze połączyć je i przesyłać proste informacje (może nawet kilka bitów) czy po prostu szukać czegoś mocniejszego aby obsługiwało wszystko. Miałby ktoś jakiś pomysł jak można by było ogarnąć temat z wykorzystaniem tego co mam, bądź co dałoby radę obsłużyć wszystkie potrzebne mi funkcje bez płacenia milionów monet? Zależy mi aby układ był stosunkowo niewielki i energooszczędny. Z góry dziękuję za wszystkie sugestie i pomysły oraz proszę o wyrozumiałość nie jestem aż tak biegły w temacie jak niektórzy doświadczeni użytkownicy i pasjonaci. Pozdrawiam!
-
Cześć, jestem w trakcie prac nad zbieraniem sampli sygnału audio na zestawie FPGA "Sipeed Tang Nano 4K" i potrzebuje w celu debugowania układu jakiegoś kanału do komunikacji z portem szeregowym, lub Arduino. Chciałem użyć któregoś z IP Cores z "Gowin EDA" ale zarówno UART jak i "SPI Master" są tak przekombinowane, że ich użycie wymaga napisania sporej ilości kodu. Postanowiłem więc użyć zestawu FPGA "Elbert v.2" w celu napisania prostego kodu do komunikacji za pomocą protokołu SPI . Powstał więc bardzo prosty "SPI Master", który jest uruchomiony na zestawie FPGA i połączony za pomocą protokołu SPI z "Arduino UNO", które odbiera dane i wyświetla je za pomocą "Monitora portu szeregowego". Do samego kodu "SPI Master'a" został dołączony "debouncer" do przycisku i generator pojedynczego impulsu (o długości okresu zegara), który inicjuje wysłanie jednego bajtu danych. W celu wygenerowania jednego bardzo krótkiego impulsu napisałem (za pomocą kilku przerzutników typu D) i bramki AND układ generatora monostabilnego. Tutaj wynik symulacji działania generatora monostabilnego: Układ działa w ten sposób, że naciśnięcie przycisku (SW1 z Elbert'a) powoduje wysłanie jednego bajtu danych do Arduino za pomocą SPI. Tak wygląda układ testowy (potrzebny był poza FPGA i Arduino 4-liniowy konwerter poziomów logicznych): Tutaj kod w VHDL głównego modułu (a właściwie entity) projektu - plik "lw_spi_master.vhd ": library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity lw_spi_master is generic ( c_clkfreq : integer := 12_000_000; c_sclkfreq : integer := 5_000_000; c_cpol : std_logic := '0'; c_cpha : std_logic := '0' ); Port ( clk_i : in STD_LOGIC; en_i_Low : in STD_LOGIC; mosi_data_i : in STD_LOGIC_VECTOR (7 downto 0); miso_data_o : out STD_LOGIC_VECTOR (7 downto 0); data_ready_o : out STD_LOGIC; cs_o : out STD_LOGIC; sclk_o : out STD_LOGIC; mosi_o : out STD_LOGIC; miso_i : in STD_LOGIC ); end lw_spi_master; architecture Behavioral of lw_spi_master is component debounce is port ( clk : IN STD_LOGIC; --input clock button : IN STD_LOGIC; --input signal to be debounced result : OUT STD_LOGIC); --debounced signal end component; component monostable_ff is port( mono_pulse : out std_logic; clk : in std_logic; reset: in std_logic; key :in std_logic ); end component; signal write_reg : std_logic_vector (7 downto 0) := (others => '0'); signal read_reg : std_logic_vector (7 downto 0) := (others => '0'); signal en_i : std_logic := '0'; signal sclk_en : std_logic := '0'; signal sclk : std_logic := '0'; signal sclk_prev : std_logic := '0'; signal sclk_rise : std_logic := '0'; signal sclk_fall : std_logic := '0'; signal pol_phase : std_logic_vector (1 downto 0) := (others => '0'); signal mosi_en : std_logic := '0'; signal miso_en : std_logic := '0'; signal en_i_DB : std_logic; signal cnt : std_logic_vector (10 downto 0) := (others => '0'); constant c_edgecntrlimdiv2 : integer := c_clkfreq/(c_sclkfreq*2); signal edgecntr : integer range 0 to c_edgecntrlimdiv2 := 0; signal cntr : integer range 0 to 15 := 0; signal small_cnt : integer range 0 to 1000 := 0; signal blokada : integer range 0 to 3 := 0; type states is (S_IDLE, S_TRANSFER); signal state : states := S_IDLE; -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- begin C1: debounce port map (clk_i,en_i_Low, en_i_DB); C2: monostable_ff port map ( mono_pulse => en_i, clk => clk_i, reset => '1', key => not en_i_DB ); --en_i <= not(en_i_DB); pol_phase <= c_cpol & c_cpha; P_SAMPLE_EN : process (pol_phase, sclk_fall, sclk_rise) begin case pol_phase is when "00" => mosi_en <= sclk_fall; miso_en <= sclk_rise; when "01" => mosi_en <= sclk_rise; miso_en <= sclk_fall; when "10" => mosi_en <= sclk_rise; miso_en <= sclk_fall; when "11" => mosi_en <= sclk_fall; miso_en <= sclk_rise; when others => end case; end process; P_RISEFALL_DETECT : process (sclk, sclk_prev) begin if (sclk = '1' and sclk_prev = '0') then sclk_rise <= '1'; else sclk_rise <= '0'; end if; if (sclk = '0' and sclk_prev = '1') then sclk_fall <= '1'; else sclk_fall <= '0'; end if; end process; P_MAIN : process (clk_i) begin if (rising_edge(clk_i)) then sclk_prev <= sclk; case state is when S_IDLE => cs_o <= '1'; mosi_o <= '0'; data_ready_o <= '0'; sclk_en <= '0'; cntr <= 0; if (c_cpol = '0') then sclk_o <= '0'; else sclk_o <= '1'; end if; if (en_i = '1') then state <= S_TRANSFER; sclk_en <= '1'; write_reg <= mosi_data_i; mosi_o <= mosi_data_i(7); read_reg <= x"00"; end if; when S_TRANSFER => cs_o <= '0'; mosi_o <= write_reg(7); if (c_cpha = '1') then if (cntr = 0) then sclk_o <= sclk; if (miso_en = '1') then read_reg(0) <= miso_i; read_reg(7 downto 1) <= read_reg(6 downto 0); cntr <= cntr + 1; end if; elsif (cntr = 8) then data_ready_o <= '1'; miso_data_o <= read_reg; if (mosi_en = '1') then data_ready_o <= '0'; if (en_i = '1') then write_reg <= mosi_data_i; mosi_o <= mosi_data_i(7); sclk_o <= sclk; cntr <= 0; else state <= S_IDLE; cs_o <= '1'; end if; end if; elsif (cntr = 9) then if (miso_en = '1') then state <= S_IDLE; cs_o <= '1'; end if; else sclk_o <= sclk; if (miso_en = '1') then read_reg(0) <= miso_i; read_reg(7 downto 1) <= read_reg(6 downto 0); cntr <= cntr + 1; end if; if (mosi_en = '1') then mosi_o <= write_reg(7); write_reg(7 downto 1) <= write_reg(6 downto 0); end if; end if; else -- c_cpha = '0' if (cntr = 0) then sclk_o <= sclk; if (miso_en = '1') then read_reg(0) <= miso_i; read_reg(7 downto 1) <= read_reg(6 downto 0); cntr <= cntr + 1; end if; elsif (cntr = 8) then data_ready_o <= '1'; miso_data_o <= read_reg; sclk_o <= sclk; if (mosi_en = '1') then data_ready_o <= '0'; if (en_i = '1') then write_reg <= mosi_data_i; mosi_o <= mosi_data_i(7); cntr <= 0; else cntr <= cntr + 1; end if; if (miso_en = '1') then state <= S_IDLE; cs_o <= '1'; end if; end if; elsif (cntr = 9) then if (miso_en = '1') then state <= S_IDLE; cs_o <= '1'; end if; else sclk_o <= sclk; if (miso_en = '1') then read_reg(0) <= miso_i; read_reg(7 downto 1) <= read_reg(6 downto 0); cntr <= cntr + 1; end if; if (mosi_en = '1') then write_reg(7 downto 1) <= write_reg(6 downto 0); end if; end if; end if; end case; end if; end process; P_SCLK_GEN : process (clk_i) begin if (rising_edge(clk_i)) then if (sclk_en = '1') then if edgecntr = c_edgecntrlimdiv2-1 then sclk <= not sclk; edgecntr <= 0; else edgecntr <= edgecntr + 1; end if; else edgecntr <= 0; if (c_cpol = '0') then sclk <= '0'; else sclk <= '1'; end if; end if; end if; end process; end Behavioral; W tym pliku jest zawarta cała implementacja "SPI Master'a". Widać też użycia komponentów "debouncer'a" i generatora monostabilnego. Tutaj kod "deuboncer'a": LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY debounce IS GENERIC( counter_size : INTEGER := 20); --counter size (19 bits gives 10.5ms with 50MHz clock) PORT( clk : IN STD_LOGIC; --input clock button : IN STD_LOGIC; --input signal to be debounced result : OUT STD_LOGIC); --debounced signal END debounce; ARCHITECTURE logic OF debounce IS SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops SIGNAL counter_set : STD_LOGIC; --sync reset to zero SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output BEGIN counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter PROCESS(clk) BEGIN IF(clk'EVENT and clk = '1') THEN flipflops(0) <= button; flipflops(1) <= flipflops(0); If(counter_set = '1') THEN --reset counter because input is changing counter_out <= (OTHERS => '0'); ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met counter_out <= counter_out + 1; ELSE --stable input time is met result <= flipflops(1); END IF; END IF; END PROCESS; END logic; Tutaj kod VHDL generatora krótkiego impulsu "monostable_ff.vhd": library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity monostable_ff is port( mono_pulse : out std_logic; clk : in std_logic; reset: in std_logic; key :in std_logic ); end monostable_ff; architecture Behavioral of monostable_ff is component DFF_AsyncReset is port( Q : out std_logic; QNot : out std_logic; clk : in std_logic; reset: in std_logic; D :in std_logic ); end component; component nand2 is port(a,b : in std_logic; y : out std_logic); end component; signal Q1,Q2,Q3,Q4,Q5 : std_logic; signal Q1N,Q2N,Q3N,Q4N,Q5N : std_logic; signal s11 : std_logic; begin DFF1: DFF_AsyncReset port map ( Q => Q1, QNot => Q1N, clk => clk, reset => reset, D => key ); DFF2: DFF_AsyncReset port map ( Q => Q2, QNot => Q2N, clk => clk, reset => reset, D => Q1 ); DFF3: DFF_AsyncReset port map ( Q => Q3, QNot => Q3N, clk => clk, reset => reset, D => Q2 ); DFF4: DFF_AsyncReset port map ( Q => Q4, QNot => Q4N, clk => clk, reset => reset, D => Q3 ); DFF5: DFF_AsyncReset port map ( Q => Q5, QNot => Q5N, clk => clk, reset => reset, D => Q4 ); mono_pulse <= (Q1 and Q5N); end Behavioral; Układ jest zrobiony na "liniI opóźniającej" z kilku przerzutników typu D i dwu-wejściowej bramki "AND" (kiedyś w mojej przeszłości budowało się podobne układy na układach scalonych z serii TTL). Do budowy tego generatora monostabilnego użyłem przerzutników typu D (wejście zegarowe reaguje na zbocze narastające) z asynchronicznym resetem stanem niskim. Tutaj kod przerzutnika typu D ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity DFF_AsyncReset is port( Q : out std_logic; QNot : out std_logic; clk : in std_logic; reset: in std_logic; D :in std_logic ); end DFF_AsyncReset; architecture Behavioral of DFF_AsyncReset is begin process(clk,reset) begin if(reset='0') then Q <= '0'; QNot <= '1'; elsif(rising_edge(clk)) then Q <= D; QNot <= (not D); end if; end process; end Behavioral; A tutaj plik "user constraints" "lw-spi_master.ucf" dla zestawu Elbert v.2: CONFIG VCCAUX = "3.3" ; # Clock 12 MHz NET "clk_i" LOC = P129 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz; NET "en_i_Low" LOC = P80 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #SW1 # mosi_data_i : in STD_LOGIC_VECTOR (7 downto 0); DIPSwitch NET "mosi_data_i[7]" LOC = P70 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[6]" LOC = P69 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[5]" LOC = P68 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[4]" LOC = P64 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[3]" LOC = P63 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[2]" LOC = P60 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[1]" LOC = P59 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "mosi_data_i[0]" LOC = P58 | PULLUP | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; # miso_data_o : out STD_LOGIC_VECTOR (7 downto 0); LEDs NET "miso_data_o[7]" LOC = P46 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[6]" LOC = P47 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[5]" LOC = P48 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[4]" LOC = P49 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[3]" LOC = P50 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[2]" LOC = P51 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[1]" LOC = P54 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; NET "miso_data_o[0]" LOC = P55 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #################################################################################################### # HEADER P1 #################################################################################################### # sclk_o : out STD_LOGIC; NET "sclk_o" LOC = P31 | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 12; #1 # mosi_o : out STD_LOGIC; NET "mosi_o" LOC = P32 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #2 # miso_i : in STD_LOGIC NET "miso_i" LOC = P28 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #3 # cs_o : out STD_LOGIC; NET "cs_o" LOC = P30 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #4 # data_ready_o : out STD_LOGIC; NET "data_ready_o" LOC = P27 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12; #5 #Port ( # clk_i : in STD_LOGIC; # en_i_Low : in STD_LOGIC; # mosi_data_i : in STD_LOGIC_VECTOR (7 downto 0); # miso_data_o : out STD_LOGIC_VECTOR (7 downto 0); # data_ready_o : out STD_LOGIC; # cs_o : out STD_LOGIC; # sclk_o : out STD_LOGIC; # mosi_o : out STD_LOGIC; # miso_i : in STD_LOGIC #); Jak widać w pliku dane (bajt), które są wysyłane magistralą SPI do Arduino UNO, są podłączone do 8-miu DIP Switchy z zestawu Elbert, a przycisk "SW1" powoduje jednorazowa wysyłkę bajtu danych. Tutaj zrzut ekranu z "monitora portu szeregowego" z ARDUINO IDE z programem do odbioru danych po SPI.: Na koniec wklejam spakowany zip'em projekt dla Xilinx "ISE 14.7". Implementacja całego projektu zajmuje poniżej 100 LUT. Wklejam opis projektu bo takie funkcje komunikacyjne przydają się w przyszłości do bardziej skomplikowanych projektów. Teraz pozostaje uruchomienie kodu na zestawie FPGA "Sipeed Tang nano 4K". LW_SPI_master_01.zip Pozdrawiam
-
SPI TFT 1.8' + NRF24l01 czyli konflikt urzadzen na wspolnym SPI
farmaceuta opublikował temat w Arduino i ESP
Witam...mam problem jak w temacie..czyli lcd z rf troszke sie "gryza" Jesli rf (z lcd) pracuje jako nadajnik to wszystko gra...jesli natomiast chcial bym odbierac dane to otrzymuje "smieci" bardzo szybko...w skrocie jedno ardu co 100ms inkrementuje bajta i go wysyla a drugie (z lcd) ma to odbierac...probowalem juz sam zarzadzac pinami CS (low = ON/ high = OFF) ale nic to nie daje... Dziwi mnie to o tyle bo myslalem ze rf.available() zwraca prawde jesli cos radiowo zostalo odebrane, a tu wychodzi ze jesli cos zostalo wyslane po SPI to rf traktuje to jako pakiet odebrany...🤔 Ma ktos jakies pomysly ciekawe? Dodam ze juz ten temat chwile walkowalem i duzo ludzi zglasza takie problemy...😕 Bede wdzieczny za jaka kolwiek pomoc😉 kod zaraz do-edytuje.. -
Czesc, udalo mi sie ostatnio napisac na blue pillu prosty voice recorder, ale przy odtwarzaniu nagrania slyszalem mase stukow (mimo to glos jest calkiem rozpoznawalny). Myslalem ze to moze byc problem z zasilaniem czy cos, ale zrzucilem sobie nagranie na program ala audacity i podejrzenie o stuki padlo na SPI. Jezeli chodzi o kod to uzywam ADC z czestotliwoscia 16kHz i wypelniam bufor o rozmiarze 512. Jak bufor jest pelny robie zapis do karty SD za pomoca biblioteki FATFS( ktorej nie jestem pewien czy uzywam poprawnie), wszystko wygenerowane w CUBEMX i zbudowane na plytce stykowej. x = ~32ms ; y = ~64ms | 512/16kHz = 0.032 s = 32 ms Nagrałem dzwiek fali sinus z glosnikow i zauwazylem ze te zaklocenia troche oddaja to co sie dzieje u mnie w kodzie, tam gdzie jest 1 na SS wyglada na to ze to jest moment gdy robie f_write do SD, a tam gdzie jest 2, dzieje sie znow f_write z kolejnym pelnym buforem + f_sync, ktory jak rozumiem robi flush danych (danych zapisanych wczesniej za pomoca f_write() ) do karty. I teraz pytanko o FATFS. Z tego co probowalem wyczytac z dokumentacji (http://elm-chan.org/fsw/ff/doc/write.html), for i wydebugowac, ta biblioteka tworzy w RAM mcu takie wirtualne odzwierciedlenie tego co jest w pliku na karcie SD w postaci struktury FILE, i teraz jak robie f_write(bufor), to to sie nie przeklada na fizyczny zapis danych do karty za pomoca SPI, tylko na przeniesienie mojego bufora do bufora struktury FILE (czyli kopia z RAM do RAM), a fizyczny zapis do SD nastepuje dopiero po wywolaniu funkcji f_sync(). Wtedy to co jest w FILE.data[] leci po SPI do karty. Dobrze to rozumiem? Czy moze f_sync() uzywac co 10 albo 100 zapis zamiast co 2? Z analizy obrazka z drugiej strony by wynikalo ze jezeli to zeczywiscie SPI tam tak miesza, to f_write() jednak dokonuje zapisu po SPI do karty SD, tylko wtedy nie rozumiem czemu w 2 dzieje sie taki meksyk, f_sync() nie powinno miec nic do wypchniecia i zaklocenia nie powinny tam trwac dwa razy to co sie dzieje w 1. Ostatecznie pytanko, czy da sie te zaklocenia ogolnie jakos wyeliminowac sprzetowo? Piąteczka
-
Cześć, to już któryś wieczór, kiedy siedzę i próbuję zrozumieć dlaczego nie mogę połączyć się z magnetometrem MMC5983MA po SPI, więc postanowiłem się podzielić problemem. Na własnej płytce mam STM32F4, kilka układów na SPI1, SPI5, które działają i nieszczęsny magnetometr MMC5983MA na SPI2, który korzysta z tych samych funkcji, lecz nie chce rozmawiać. Odbiór danych w kodzie wygląda tak: uint8_t bufferSize = 2U; uint8_t readWriteBit = 0x80; uint8_t timeout = 10U; uint8_t productIdAddress = 0x2F; uint8_t txBuffer[2] = { productIdAddress | readWriteBit, 0x00 }; uint8_t rxBuffer[2] = { 0 }; HAL_GPIO_WritePin(MMC5983MA_SPI2_CS_GPIO_Port, MMC5983MA_SPI2_CS_Pin, GPIO_PIN_RESET); HAL_SPI_TransmitReceive(&hspi2, txBuffer, rxBuffer, bufferSize, timeout); HAL_GPIO_WritePin(MMC5983MA_SPI2_CS_GPIO_Port, MMC5983MA_SPI2_CS_Pin, GPIO_PIN_SET); Na analizatorze wygląda to tak, układ w ogóle nie macha linią MISO: Konfiguracja SPI2 z CubeMX: Schemat: Sekwencja zapisu/odczytu SPI: Przykład połączenia: Rejestr, który próbuję odczytać: Mam polutowane 4 płytki i na żadnej z nich nie udało mi się nawiązać połączenia, nie jest to dowód na to, że z pcb na pewno jest wszystko w porządku, ale chciałbym najpierw potwierdzić, że sposób odczytu danych od strony programowej jest poprawny. W erracie używanego procka nie ma żadnej wzmianki, która mogłaby mieć bezpośredni związek z moim problemem. Czy ktoś ma jakiś pomysł co mogę jeszcze sprawdzić? Edit: Płytki wypiekam w piecu IR, rampa jest bardzo zbliżona do tej z dokumentacji układu magnetometru, do tej pory nie udało mi się upalić pozostałych układów, więc obstawiałbym, że proces lutowania ich nie zabija. 🙂
-
Dzień Dobry Forumowicze! Problem dotyczy zarówno mikrokontrolera, jak i RPi, więc mam nadzieje że nie będzie problemu związanego z nieodpowiednim działem. Od kilku dni borykam się bezskutecznie z pewnym problemem, a prezentuje się on następująco: Potrzebuję wymienić dane poprzez SPI między Raspberry Pi Zero W (Master), a Atmegą64(Slave). Atmega zasilana przez 5V na własnoręcznie zaprojektowanej płytce (z konwerterem poziomów logicznych 3,3V-5V na MOSFET'ach). Generalnie elektrycznie wszystko jest sprawne i sprawdzone kilkukrotnie, więc to odpada. Jestem w stanie zaprogramować AVR'a przez RPi za pośrednictwem SPI właśnie (na RPi Rasbian w wersji 9), z wykorzystaniem AVRDUDE. Problem jaki się pojawia, to przy próbie wymiany danych między nimi. AVR'a programuje w C, natomiast RPi w Pythonie (kody programów niżej). Polega on na tym, że biblioteka Python'a SpiDev, jako sygnał ChipSelect podaje stan wysoki, podczas gdy ATMEGA wymaga podczas tej komunikacji stanu niskiego. Atmega nie posiada możliwości zmiany trybu na taki, aby czytała stan wysoki, a biblioteka SpiDev z kolei, nie ma funkcjonalności podania stanu niskiego. Chciałem to obejść poprzez podpięcie nóżki Atmegi pod zupełnie inną nóżkę RPi i ręcznego wysterowywania tej nóżki przed nadaniem paczki danych, jednak to nie działa - nie wiem jednak dlaczego. Nie używałem nigdy wcześniej SPI, więc finalnie nie jestem nawet pewien gdzie leży problem - czy w kodzie Slav'a, Mastera czy zupełnie gdzie indziej. Slave (C, Amtega64): #define F_CPU 1000000UL #include<avr/io.h> #include<util/delay.h> #include<avr/interrupt.h> #define ustaw(bajt, nr_bitu) (bajt |=(1<<nr_bitu)) #define skasuj(bajt, nr_bitu) (bajt &=~(1<<nr_bitu)) #define sprawdz(bajt, nr_bitu) ((bajt &(1<<nr_bitu))&&1) #define sleep(czas) for (int i=0; i<(czas); i++) _delay_ms(1) int data=500; void init_spi(void) { DDRB=(1<<PB3); //MISO - output SPCR=(1<<SPE)|(1<<SPIE); //SPI_ON & Interrupt SPDR=0; } uint8_t rec_spi(void) { while (!(SPSR & (1<<SPIF))) ; return SPDR; //return data register } int main(void) { sei(); init_spi(); DDRC |=1<<PC3; //LED'y DDRC |=1<<PC4; DDRC |=1<<PC5; while (1) { ustaw(PORTC, PC4); sleep(data); skasuj(PORTC, PC4); sleep(data); } } ISR (SPI_STC_vect) { data = rec_spi(); ustaw(PORTC,PC5); } Master (Python, RPi): import RPi.GPIO as GPIO import spidev import time GPIO.setmode(GPIO.BCM) GPIO.setup(7, GPIO.OUT) GPIO.output(7, GPIO.HIGH) spi = spidev.SpiDev() spi.open(0, 0) print('Open SPI') #GPIO.output(7, GPIO.LOW) data = 0xAA try: while True: print('Sending..') GPIO.output(7, GPIO.LOW) spi.xfer([data], 50000, 100, 8) # spi.writebytes([250]) GPIO.output(7, GPIO.HIGH) print('complete') time.sleep(2) #end while except KeyboardInterrupt: # sleep(0.1) spi.close() GPIO.cleanup() Na masterze (RPi) próbowałem ustawiać różne tryby (spi.mode), różne prędkości, próbowałem z spi.writebytes oraz z spi.xfer. Wszystko bez skutku. Na Atmedze, mrugam diodą co pół sekundy. Próbowałem osiągnąć taki efekt, by wysłać liczbę 250 i ustawić ją jako czas mrugania, co zauważyłbym jako szybsze mruganie diody. Próbowałem też zapalić inną diodę w przerwaniu od SPI - wszystko bezskutecznie. SPI w FuseBitach jest aktywne. Połączenia elektryczne są poprawne, przy czym Atmegowski SS jest podłączony do 7 pinu RPi. Byłbym bardzo wdzięczny za wszelką pomoc i sugestie. Pozdrawiam.
-
Witajcie! Pracuje obecnie na Nucleo-F746ZG. Chce nawiązać komunikacje przez SPI z FPGA. Moje urządzenie działa jako slave. Obecnie nie jest źle, komunikacja działa poprawnie w obydwie strony. Problem jest w zasadzie prosty, FPGA wysyła mi 32 liczby 16bitowe, a ja mam je odebrać w odpowiedniej kolejności. Co wiec robie? Ustalam, że ciąg liczb powinien się zaczynać od wartości 0x01. Niestety moje próby zakończyły się niepowodzeniem. Mikrokontroler "łapie" dane w losowym momencie, stąd w moim buforze dane zaczynać się mogą od dowolnej liczby ze zbioru wszystkich 32 liczb. Można to potraktować jako przesuniecie w fazie, lecz najgorsze jest to że po "złapaniu" jest ono stale. Wiec moje ify na niewiele się zdadzą, bo jak 0x01 jest na 7 miejscu w buforze to tak już pozostanie. Mam nadzieje, że wyraziłem się względnie jasno. Zamieszczam część kodu obsługująca SPI. Używam HAL i w projekcie pomaga mi CubeMX. Będę wdzięczny za sugestie! #define WORD_LENGTH 32 /* word length */ uint16_t rx_spi5[WORD_LENGTH]; /* Buffer for received data from SPI5 */ uint16_t tx_spi5[WORD_LENGTH]; /* Buffer for sending data from SPI5 */ uint16_t trig = 0x0001; /* Trigger value */ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { if(hspi->Instance == hspi5.Instance) { //HAL_SPI_Receive_IT(&hspi5, &rx_spi5, 1); HAL_SPI_TransmitReceive_IT(&hspi5, tx_spi5, rx_spi5, WORD_LENGTH); } } while(1) { if (rx_spi5[0] == trig) { for (int i = 0; i <WORD_LENGTH; ++i) { size = sprintf(data, " %x ; ", rx_spi5[i]); HAL_UART_Transmit(&huart3, data, size, HAL_MAX_DELAY); memset(data, 0, 75); } size = sprintf(data, "\r\n"); HAL_UART_Transmit(&huart3, data, size, HAL_MAX_DELAY); memset(data, 0, 75); } }
-
STM32 + CubeMX + LIS3DHH - brak odbioru danych przez SPI
przemof-s opublikował temat w Mikrokontrolery
Witam, próbuję uruchomić akcelerometr LIS3DHH ( https://www.st.com/en/mems-and-sensors/lis3dhh.html) na zestawie Nucleo F411RE (https://www.st.com/en/evaluation-tools/nucleo-f411re.html). Czujnik mam w postaci adaptera STEVAL-MKI180V1 (https://www.st.com/en/evaluation-tools/steval-mki180v1.html). Konfigurację dla mikrokontrolera generuję za pomocą CubeMX 5.0.1 z bibliotekami HAL dla rodziny STM32F4, w wersji 1.23.0. Próbę uruchomienia czujnika rozpocząłem od wykorzystania bibliotek: https://github.com/STMicroelectronics/STMems_Standard_C_drivers/tree/master/lis3dhh_STdC, a dokładnie od przykładu: read_data_simple.c. Po dużej liczbie nieudanych prób komunikacji, maksymalnie uprościłem przykład. Aktualnie próbuję odczytać wartość rejestru WHO_AM_I. Adres rejestru to: 0x0F. Podczas odczytu danych, bit SMB adresu powinien mieć wartość 1, więc modyfikuję adres rejestru do wartości 0x8F. Wartość rejestru WHO_AM_I powinna wynosić 0x11, a ja otrzymuję wartość 0x00. Wszystkie linie SPI są sprzętowo podciągnięte do plusa zasilania, za pomocą wewnętrznych rezystorów mikrokontrolera. Korzystam z SPI2. Jego konfiguracja to: CPOL = High, CPHA = 2 Edge, prędkość: 1.3125 Mbits/s. Sygnał CS jest generowany programowo. Poniżej przedstawiam fragment kodu źródłowego odpowiedzialnego za inicjalizację SPI oraz próbę odczytania rejestru WHO_AM_I. Inicjalizacja SPI: void MX_SPI2_Init(void) { hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; hspi2.Init.DataSize = SPI_DATASIZE_8BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi2.Init.TIMode = SPI_TIMODE_DISABLE; hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi2.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi2) != HAL_OK) { Error_Handler(); } } [Próba odczytu zawartości rejestru WHO_AM_I (zawarte w funkcji main): MX_GPIO_Init(); MX_SPI2_Init(); HAL_Delay(10); HAL_StatusTypeDef status; uint8_t reg = 0x0F; // Adres rejestru WHO_AM_I uint8_t bufp[3]; uint16_t len = 1; reg |= 0x80; // Informacja, ze przeprowadzany bedzie odczyt danych HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET); // Aktywacja SPI status = HAL_SPI_Transmit(&LIS3DHH_HANDLE, ®, 1, 1000); // Wyslanie adresu do odczytu status = HAL_SPI_Receive(&LIS3DHH_HANDLE, bufp, len, 1000); // Odbior zawartosci adresu HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET); // Dezaktywacja SPI W załączniku przedstawiam przebiegi uzyskane z analizatora stanów logicznych, plik konfiguracyjny dla CubeMX oraz kod źródłowy programu testowego. Dodam, że testy przeprowadzałem na dwóch czujnikach, oraz dodatkowo na zestawie z mikrokontrolerem STM32F103 (blue PCB). Modyfikowałem na wiele sposobów konfigurację SPI oraz odczyt rejestrów. Efekt za każdym razem taki sam. Czy ktoś ma pomysł co robię nie tak, że za każdym razem otrzymuję wartość zero z rejestru WHO_AM_I? Test_LIS3DHH_F4.zip -
Posiadam płytkę STM32F407G-DISC1 oraz ekspander MCP23S08. Na podstawie kursu STM32F4 oraz STM32F1 próbuję zapalić diodę na wyjściu ekspandera. Korzystam z CUBEMX do konfiguracji mikrokontrolera oraz eclipse'a do programowania. Mam wrażenie, że wszystko robię w poprawny sposób, konfiguracja SPI jest zgodna z tą pokazaną w 9 części kursu STM32F1 a mimo to wyjścia ekspandera pozostają nieaktywne. Oczekuję, że zapali się dioda podpięta do pinu GP0. Poniżej dołączam mój kod: /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f4xx_hal.h" /* USER CODE BEGIN Includes */ #define MCP_IODIR 0x00 #define MCP_OLAT 0x0a /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ SPI_HandleTypeDef hspi1; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_SPI1_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ void mcp_write_reg(uint8_t addr, uint8_t value) { uint8_t tx_buff[]={0x40, addr, value}; HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, tx_buff, 3, HAL_MAX_DELAY); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); } /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_SPI1_Init(); /* USER CODE BEGIN 2 */ mcp_write_reg(MCP_IODIR, ~0x01); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ mcp_write_reg(MCP_OLAT, 0x01); while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 64; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV8; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* SPI1 init function */ static void MX_SPI1_Init(void) { /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : CS_Pin */ GPIO_InitStruct.Pin = CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : DC_Pin */ GPIO_InitStruct.Pin = DC_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(DC_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : RESET_Pin */ GPIO_InitStruct.Pin = RESET_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(RESET_GPIO_Port, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void _Error_Handler(char * file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/