リビジョン | 46 (tree) |
---|---|
日時 | 2021-01-19 04:29:50 |
作者 | derekwildstar |
Unit UBCMHost.pas criada e adicionada ao projeto. Esta unit deveria pertencer a alguma biblioteca geral, pois ela fornece funções que são usadas em PasRipherals, mas que são genéricas. Quem sabe um dia eu não crie um Krakatoa para o Pi?
Funções para obtenção de informaçes do RPI adicionadas
A função PeripheralsBaseAddressAndSize foi alterada para usar as funçes exportadas por UBCMHost, que são mais simples e eficientes
A função GetInfo foi atualizada para retornar informações referentes ao PI
@@ -0,0 +1,82 @@ | ||
1 | +unit UBCMHost; | |
2 | +{:< Esta unit é a tradução literal do cabeçalho bcm_host.h, que contém funções | |
3 | +úteis para obtenção de informações sobre o RPI. Para que esta unit seja | |
4 | +compilada, inclua no library path (-Fl) do projeto o caminho onde libbcm_host.so | |
5 | +está /opt/vc/lib (pasta de bibliotecas do firmware do RPI). Cuidado ao usar as | |
6 | +funçes desta biblioteca, pois aparentemente algumas delas ainda no consideram o | |
7 | +Pi4, por exemplo, bcm_host_get_processor_id retorna BCM_HOST_PROCESSOR_BCM2838 | |
8 | +no Pi4, porém este Pi tem um BCM2711 de acordo com cat/cpuinfo. Realmente não | |
9 | +sei se está certo ou não, pois o Pi3 anterior tinha um BCM2835, logo, como o Pi4 | |
10 | +tem um BCM2711 } | |
11 | +{$mode objfpc}{$H+} | |
12 | + | |
13 | +interface | |
14 | + | |
15 | +procedure bcm_host_init; cdecl; | |
16 | +procedure bcm_host_deinit; cdecl; | |
17 | +function graphics_get_display_size(const display_number: UINT16; width: PUINT32; height: PUINT32): INT32; cdecl; | |
18 | +function bcm_host_get_peripheral_address: UINT32; cdecl; | |
19 | +function bcm_host_get_peripheral_size: UINT32; cdecl; | |
20 | +function bcm_host_get_sdram_address: UINT32; cdecl; | |
21 | + | |
22 | +{: Retorna o tipo de Pi sendo usado } | |
23 | +function bcm_host_get_model_type: INT32; cdecl; | |
24 | + | |
25 | +const | |
26 | + BCM_HOST_BOARD_TYPE_MODELA = 0; | |
27 | + BCM_HOST_BOARD_TYPE_MODELB = 1; | |
28 | + BCM_HOST_BOARD_TYPE_MODELAPLUS = 2; | |
29 | + BCM_HOST_BOARD_TYPE_MODELBPLUS = 3; | |
30 | + BCM_HOST_BOARD_TYPE_PI2MODELB = 4; | |
31 | + BCM_HOST_BOARD_TYPE_ALPHA = 5; | |
32 | + BCM_HOST_BOARD_TYPE_CM = 6; | |
33 | + BCM_HOST_BOARD_TYPE_CM2 = 7; | |
34 | + BCM_HOST_BOARD_TYPE_PI3MODELB = 8; | |
35 | + BCM_HOST_BOARD_TYPE_PI0 = 9; | |
36 | + BCM_HOST_BOARD_TYPE_CM3 = $0A; | |
37 | + BCM_HOST_BOARD_TYPE_CUSTOM = $0B; | |
38 | + BCM_HOST_BOARD_TYPE_PI0W = $0C; | |
39 | + BCM_HOST_BOARD_TYPE_PI3MODELBPLUS = $0D; | |
40 | + BCM_HOST_BOARD_TYPE_PI3MODELAPLUS = $0E; | |
41 | + BCM_HOST_BOARD_TYPE_FPGA = $0F; | |
42 | + BCM_HOST_BOARD_TYPE_CM3PLUS = $10; | |
43 | + BCM_HOST_BOARD_TYPE_PI4MODELB = $11; | |
44 | + | |
45 | +{: Retorna True se é um Pi4 } | |
46 | +function bcm_host_is_model_pi4: Boolean; cdecl; | |
47 | + | |
48 | +{: Retorna True se fkms estiver ativo (dtoverlay=v3d-fkms-vc4) } | |
49 | +function bcm_host_is_fkms_active: Boolean; cdecl; | |
50 | + | |
51 | +{: Retorna True se kms estiver ativo (dtoverlay=v3d-kms-vc4) } | |
52 | +function bcm_host_is_kms_active: Boolean; cdecl; | |
53 | + | |
54 | +{: Retorna o ID do processador } | |
55 | +function bcm_host_get_processor_id: INT32; cdecl; | |
56 | + | |
57 | +const | |
58 | + BCM_HOST_PROCESSOR_BCM2835 = 0; | |
59 | + BCM_HOST_PROCESSOR_BCM2836 = 1; | |
60 | + BCM_HOST_PROCESSOR_BCM2837 = 2; | |
61 | + BCM_HOST_PROCESSOR_BCM2838 = 3; | |
62 | + | |
63 | +implementation | |
64 | + | |
65 | +const | |
66 | + BCMHost = 'bcm_host'; | |
67 | + | |
68 | +procedure bcm_host_init; cdecl; external BCMHost; | |
69 | +procedure bcm_host_deinit; cdecl; external BCMHost; | |
70 | +function graphics_get_display_size(const display_number: UINT16; width: PUINT32; height: PUINT32): INT32; cdecl; external BCMHost; | |
71 | +function bcm_host_get_peripheral_address: UINT32; cdecl; external BCMHost; | |
72 | +function bcm_host_get_peripheral_size: UINT32; cdecl; external BCMHost; | |
73 | +function bcm_host_get_sdram_address: UINT32; cdecl; external BCMHost; | |
74 | + | |
75 | +function bcm_host_get_model_type: INT32; cdecl; external; | |
76 | +function bcm_host_is_model_pi4: Boolean; cdecl; external; | |
77 | +function bcm_host_is_fkms_active: Boolean; cdecl; external; | |
78 | +function bcm_host_is_kms_active: Boolean; cdecl; external; | |
79 | +function bcm_host_get_processor_id: INT32; cdecl; external; | |
80 | + | |
81 | +end. | |
82 | + |
@@ -5,6 +5,11 @@ | ||
5 | 5 | |
6 | 6 | interface |
7 | 7 | |
8 | +{ | |
9 | +* Referências úteis (inclua na ajuda no futuro) | |
10 | +* https://www.iot-programmer.com/index.php/books/22-raspberry-pi-and-the-iot-in-c/chapters-raspberry-pi-and-the-iot-in-c/59-raspberry-pi-and-the-iot-in-c-memory-mapped-gpio | |
11 | +} | |
12 | + | |
8 | 13 | uses |
9 | 14 | Classes, SysUtils; |
10 | 15 |
@@ -18,7 +23,8 @@ | ||
18 | 23 | { Abaixo, rpi4.doc indica que a documentação precisa ser atualizada para o |
19 | 24 | rpi4. Futuramente troque doc.ok, por rpi3.doc.ok. caso a documentação só faça |
20 | 25 | sentido no rpi4, use rpi4.doc.ok. Verifique depois como lidar com documentação |
21 | - alternativa no PasDOC } | |
26 | + alternativa no PasDOC. Eu recomendo que seja feita uma revisão linha a linha | |
27 | + principalmente naquelas que mapeiam caracterísiticas físicas do RPI } | |
22 | 28 | |
23 | 29 | { Para criar um novo record de periférico, inclua de forma privada um ou mais |
24 | 30 | campos para o seletor (no caso de haver mais de um periférico do mesmo tipo) e |
@@ -88,6 +94,8 @@ | ||
88 | 94 | end; |
89 | 95 | |
90 | 96 | (* doc.ok *) |
97 | + (* rpi4.doc O RPI4 tem 58 GPIOs, mas estes 4 GPIOs a mais no tem função, logo | |
98 | + acredito que seja apenas questão de mudar a enumeração abaixo *) | |
91 | 99 | //: Este tipo define um subconjunto de números que variam de 0 a 53 e que |
92 | 100 | //: serve para representar cada um dos 54 GPIOs disponíveis no Raspberry PI 3 |
93 | 101 | //: (segundo o datasheet do BCM2837). |
@@ -601,6 +609,11 @@ | ||
601 | 609 | end; |
602 | 610 | |
603 | 611 | (* doc.ok *) |
612 | + (* rpi4.doc No RPI4 existem 8 controladores BSC, dentre os quais o BSC2 e o | |
613 | + BSC7 são dedicados para uso com HDMI. Provavelmente existem GPIOs para acesso | |
614 | + aos novos BSC, consulte o datasheet. A enumeração abaixo provavelmente vai | |
615 | + precisar ser alterada no RPI4 *) | |
616 | + | |
604 | 617 | //: Existem 3 controladores BSC principais: BSC0, BSC1 e BSC2. O BSC2 é usado |
605 | 618 | //: exclusivamente pelo HDMI e não deve ser usado em programas, por isso |
606 | 619 | //: apenas os controladores 0 e 1 são acessíveis. O BSC1 encontra-se nos GPIO |
@@ -610,7 +623,7 @@ | ||
610 | 623 | //: |
611 | 624 | //: Algumas implementações acessam o I2C por meio de um file descriptor e |
612 | 625 | //: execuções da função "ioctl". A título de informação, o dispositivo |
613 | - //: "/dev/i2c-1" correspomde ao BSC1. Esta enumeração lista apenas os | |
626 | + //: "/dev/i2c-1" corresponde ao BSC1. Esta enumeração lista apenas os | |
614 | 627 | //: controladores que são efetivamente acessáveis, atualmente o BSC0 e o BSC1 |
615 | 628 | //: @Value(icBSC0 Indica que estamos acessando o controlador 0) |
616 | 629 | //: @Value(icBSC1 Indica que estamos acessando o controlador 1, também |
@@ -1007,6 +1020,7 @@ | ||
1007 | 1020 | //: dois dispositivos simultaneamente no mesmo programa) |
1008 | 1021 | TCustomPasRipherals = class |
1009 | 1022 | private |
1023 | + FCPUInfo: String; | |
1010 | 1024 | FPeripherals: PUInt32; |
1011 | 1025 | FRunningAsRoot: Boolean; |
1012 | 1026 |
@@ -1018,6 +1032,12 @@ | ||
1018 | 1032 | function GetLevels(ALevelBank: TPRGPIOLevelBank): UInt32; |
1019 | 1033 | function GetModes(AModeBank: TGPIOModeBank): UInt32; |
1020 | 1034 | function GetState: TSavedState; |
1035 | + | |
1036 | + function GetCPUInfo: String; | |
1037 | + function GetHardware: String; | |
1038 | + function GetRevision: String; | |
1039 | + function GetSerial: String; | |
1040 | + function GetModel: String; | |
1021 | 1041 | function GetInfo: String; |
1022 | 1042 | |
1023 | 1043 | procedure SetLevels(ALevelBank: TPRGPIOLevelBank; ALevels: UInt32); |
@@ -1032,7 +1052,9 @@ | ||
1032 | 1052 | |
1033 | 1053 | //: Use esta função para obter uma máscara com as características indicadas |
1034 | 1054 | function GetBitsMask(ABitIndex: UInt8; ABitsCount: UInt8): UInt32; |
1035 | - | |
1055 | + //: Use esta função para obter o endereço base dos periféricos e seu | |
1056 | + //: tamanho. Essas informações são usadas no mapeamento da memória, durante | |
1057 | + //: a criaço de um instância da classe atual | |
1036 | 1058 | procedure PeripheralsBaseAddressAndSize(out ABaseAdddress: UInt32; out ASize: UInt32); |
1037 | 1059 | |
1038 | 1060 | procedure NanoSleep(ANanoSeconds: Uint16); |
@@ -1052,6 +1074,7 @@ | ||
1052 | 1074 | property GPIOLevels[ALevelBank: TPRGPIOLevelBank]: UInt32 read GetLevels write SetLevels; |
1053 | 1075 | property GPIOModes[AModeBank: TGPIOModeBank]: UInt32 read GetModes write SetModes; |
1054 | 1076 | property State: TSavedState read GetState write SetState; |
1077 | + | |
1055 | 1078 | property Info: String read GetInfo; |
1056 | 1079 | public |
1057 | 1080 | constructor Create; virtual; |
@@ -1106,7 +1129,7 @@ | ||
1106 | 1129 | implementation |
1107 | 1130 | |
1108 | 1131 | uses |
1109 | - StrUtils, Math, BaseUnix, Errors; | |
1132 | + StrUtils, Math, BaseUnix, Errors, RegExpr, UBCMHost; | |
1110 | 1133 | |
1111 | 1134 | const |
1112 | 1135 | // A senha é usada em algumas situações e corresponde ao binário |
@@ -1132,7 +1155,9 @@ | ||
1132 | 1155 | // eles não são usados diretamente, e sim em termos de bytes a partir do |
1133 | 1156 | // início da memória mapeada, no caso de uma inicialização com privilégios |
1134 | 1157 | // administrativos, por isso as constantes com o mesmo nome, mas com sufixo |
1135 | - // "OFFSET" (mais adiante) é que são usadas | |
1158 | + // "OFFSET" (mais adiante) é que são usadas. A saída do comando | |
1159 | + // "sudo cat /proc/iomem" mostra alguns destes endereços, concatenados com o | |
1160 | + // endereço base de periféricos ($3F000000 no Pi3 e $FE000000 no Pi4) | |
1136 | 1161 | CLOCK_BASE = $101000; |
1137 | 1162 | GPIO_BASE = $200000; |
1138 | 1163 | BSC0_BASE = $205000; |
@@ -2412,8 +2437,9 @@ | ||
2412 | 2437 | FRunningAsRoot := FpGetuid = 0; |
2413 | 2438 | |
2414 | 2439 | // Caso o usuário seja root, usamos /dev/mem que tem acesso completo a |
2415 | - // memória, do contrário /dev/gpiomem que só é capaz de manipular os | |
2416 | - // registradores do GPIO | |
2440 | + // memória e a todos os periféricos, do contrário usamos /dev/gpiomem que só é | |
2441 | + // capaz de manipular os registradores do GPIO, único perifério acessível | |
2442 | + // neste caso | |
2417 | 2443 | if FRunningAsRoot then |
2418 | 2444 | PeripheralsFileDescriptor := FpOpen('/dev/mem', O_RDWR or O_SYNC) |
2419 | 2445 | else |
@@ -2426,18 +2452,18 @@ | ||
2426 | 2452 | // 4096 bytes. Caso len tenha valores de 4097 a 8192, Fpmmap vai ler 8192 |
2427 | 2453 | // bytes e assim sucessivamente. Isso acontece porque esta função lê |
2428 | 2454 | // páginas de tamanho fixo e igual a múltiplos de 4096. Ao carregarmos |
2429 | - // apenas o GPIO, a memória necessária é de apenas 180 Bytes ($B4), de | |
2455 | + // apenas o GPIO, a memória necessária é de apenas 179 Bytes ($B3), de | |
2430 | 2456 | // acordo com a saída de sudo cat /proc/iomem, que é menor que 4096 e |
2431 | 2457 | // portanto, usar este valor de forma fixa quando /dev/gpiomem for usado, |
2432 | 2458 | // é satisfatório. Quando estamos rodando o programa como root, usamos |
2433 | - // "PeripheralsSize" e "PeripheralsBaseAddressAndSize div PAGE_SIZE" como | |
2434 | - // offset porque a função FpMMap é equivalente a função de api mmap2, onde | |
2435 | - // o último parâmetro não representa um offset em bytes, mas sim em | |
2436 | - // páginas de tamanho fixo e igual a 4K. No RPI3 PeripheralsBaseAddress é | |
2437 | - // $3F000000 e se estivéssemos usando uma função equivalente a mmap apenas | |
2438 | - // este valor seria suficiente em Offset, mas como a função FpMMap é um | |
2439 | - // alias para mmap2, precisamos dividir esse valor pelo tamanho da página | |
2440 | - // (4096) | |
2459 | + // "PeripheralsSize" e "PeripheralsBaseAddress div PAGE_SIZE" como offset | |
2460 | + // porque a função FpMMap é equivalente a função de api mmap2, onde o | |
2461 | + // último parâmetro não representa um offset em bytes, mas sim em páginas | |
2462 | + // de tamanho fixo e igual a 4K. No RPI3, por exemplo, | |
2463 | + // PeripheralsBaseAddress é $3F000000 e se estivéssemos usando uma função | |
2464 | + // equivalente a mmap apenas este valor seria suficiente em Offset, mas | |
2465 | + // como a função FpMMap é um alias para mmap2, precisamos dividir esse | |
2466 | + // valor pelo tamanho da página (4096) | |
2441 | 2467 | if not FRunningAsRoot then |
2442 | 2468 | FPeripherals := FpMMap(nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, PeripheralsFileDescriptor, 0) |
2443 | 2469 | else |
@@ -2460,11 +2486,9 @@ | ||
2460 | 2486 | //WriteLn('Endereço que contém o nome: ',IntToHex(UInt32(GPIOBaseAddress + (($110 and $000FFFFF) shr 2)),10)); |
2461 | 2487 | //WriteLn( |
2462 | 2488 | // |
2463 | - //(GPIOBaseAddress + (($110 and $000FFFFF) shr 2))^ | |
2489 | + //PChar(GPIOBaseAddress + (($110 and $000FFFFF) shr 2)) | |
2464 | 2490 | // |
2465 | 2491 | //); |
2466 | - | |
2467 | - | |
2468 | 2492 | //////////////// |
2469 | 2493 | |
2470 | 2494 |
@@ -2588,8 +2612,109 @@ | ||
2588 | 2612 | end; |
2589 | 2613 | end; |
2590 | 2614 | |
2615 | +function TCustomPasRipherals.GetCPUInfo: String; | |
2616 | +const | |
2617 | + CPUINFO_PATH = '/proc/cpuinfo'; | |
2618 | +var | |
2619 | + LCPUInfo: TextFile; | |
2620 | + Line: String; | |
2621 | +begin | |
2622 | + Result := ''; | |
2623 | + | |
2624 | + if FCPUInfo = '' then | |
2625 | + begin | |
2626 | + AssignFile(LCPUInfo,CPUINFO_PATH); | |
2627 | + try | |
2628 | + Filemode := fmOpenRead; | |
2629 | + Reset(LCPUInfo); | |
2630 | + | |
2631 | + while not Eof(LCPUInfo) do | |
2632 | + begin | |
2633 | + ReadLn(LCPUInfo,Line); | |
2634 | + FCPUInfo := FCPUInfo + Line + #10; | |
2635 | + end; | |
2636 | + | |
2637 | + FCPUInfo := Trim(FCPUInfo); | |
2638 | + finally | |
2639 | + CloseFile(LCPUInfo); | |
2640 | + end; | |
2641 | + end; | |
2642 | + | |
2643 | + Result := FCPUInfo; | |
2644 | +end; | |
2645 | + | |
2646 | +function TCustomPasRipherals.GetHardware: String; | |
2647 | +begin | |
2648 | + Result := ''; | |
2649 | + | |
2650 | + with TRegExpr.Create('Hardware\s*:\s*(.*)') do | |
2651 | + try | |
2652 | + ModifierS := False; | |
2653 | + | |
2654 | + if Exec(GetCPUInfo) then | |
2655 | + Result := Trim(Match[1]); | |
2656 | + finally | |
2657 | + Free; | |
2658 | + end; | |
2659 | +end; | |
2660 | + | |
2661 | +function TCustomPasRipherals.GetRevision: String; | |
2662 | +begin | |
2663 | + Result := ''; | |
2664 | + | |
2665 | + with TRegExpr.Create('Revision\s*:\s*(.*)') do | |
2666 | + try | |
2667 | + ModifierS := False; | |
2668 | + | |
2669 | + if Exec(GetCPUInfo) then | |
2670 | + Result := Trim(Match[1]); | |
2671 | + finally | |
2672 | + Free; | |
2673 | + end; | |
2674 | +end; | |
2675 | + | |
2676 | +function TCustomPasRipherals.GetSerial: String; | |
2677 | +begin | |
2678 | + Result := ''; | |
2679 | + | |
2680 | + with TRegExpr.Create('Serial\s*:\s*(.*)') do | |
2681 | + try | |
2682 | + ModifierS := False; | |
2683 | + | |
2684 | + if Exec(GetCPUInfo) then | |
2685 | + Result := Trim(Match[1]); | |
2686 | + finally | |
2687 | + Free; | |
2688 | + end; | |
2689 | +end; | |
2690 | + | |
2691 | +function TCustomPasRipherals.GetModel: String; | |
2692 | +begin | |
2693 | + Result := ''; | |
2694 | + | |
2695 | + with TRegExpr.Create('Model\s*:\s*(.*)') do | |
2696 | + try | |
2697 | + ModifierS := False; | |
2698 | + | |
2699 | + if Exec(GetCPUInfo) then | |
2700 | + Result := Trim(Match[1]); | |
2701 | + finally | |
2702 | + Free; | |
2703 | + end; | |
2704 | +end; | |
2705 | + | |
2591 | 2706 | function TCustomPasRipherals.GetInfo: String; |
2592 | 2707 | // ----------------------------------------------------------------------------- |
2708 | +procedure RPIInfo; | |
2709 | +begin | |
2710 | + Result += '╔═══════════════════════════════════════════════════════════════════════════╗'#13#10; | |
2711 | + Result += '║ Model.........: ' + Format('%-58s',[GetModel]) + '║'#13#10; | |
2712 | + Result += '║ SoC...........: ' + Format('%-58s',[GetHardware]) + '║'#13#10; | |
2713 | + Result += '║ Revision......: ' + Format('%-58s',[GetRevision]) + '║'#13#10; | |
2714 | + Result += '║ Serial Number.: ' + Format('%-58s',[GetSerial]) + '║'#13#10; | |
2715 | + Result += '╚═══════════════════════════════════════════════════════════════════════════╝'#13#10; | |
2716 | +end; | |
2717 | + | |
2593 | 2718 | procedure GPIOInfo; |
2594 | 2719 | const |
2595 | 2720 | INFOLINE = '║ %-11u ║ %-19s ║ %-6s ║ %-14s ║ %-11s ║'; |
@@ -2668,6 +2793,7 @@ | ||
2668 | 2793 | // ----------------------------------------------------------------------------- |
2669 | 2794 | begin |
2670 | 2795 | Result := ''; |
2796 | + RPIInfo; | |
2671 | 2797 | GPIOInfo; |
2672 | 2798 | |
2673 | 2799 | if FRunningAsRoot then |
@@ -2699,9 +2825,9 @@ | ||
2699 | 2825 | |
2700 | 2826 | function TCustomPasRipherals.ClockBaseAddress: PUInt32; |
2701 | 2827 | begin |
2702 | - // O DataSheet não faz uma referência ao endereço base usado aqui para o | |
2703 | - // clock. Nas páginas 107 e 108 existem 6 endereços que pouco tem a ver com | |
2704 | - // CLOCK_BASE, no entanto as bibliotecas WiringPi e BCM2835 usam o mesmo | |
2828 | + // O DataSheet do BCM2835 não faz uma referência ao endereço base usado aqui | |
2829 | + // para o clock. Nas páginas 107 e 108 existem 6 endereços que pouco tem a ver | |
2830 | + // com CLOCK_BASE, no entanto as bibliotecas WiringPi e BCM2835 usam o mesmo | |
2705 | 2831 | // offset e por isso eu assumi como verdade. Ainda sobre os endereços que |
2706 | 2832 | // constam no datasheet, eles foram agrupados por tipo (CTL e DIV), e isso |
2707 | 2833 | // causa uma certa confusão. Na verdade existem 6 registradores de 32 bits |
@@ -2716,35 +2842,63 @@ | ||
2716 | 2842 | Result := FPeripherals + CLOCK_BASE_OFFSET; |
2717 | 2843 | end; |
2718 | 2844 | |
2719 | -procedure TCustomPasRipherals.PeripheralsBaseAddressAndSize(out ABaseAdddress: UInt32; out ASize: UInt32); | |
2720 | -const | |
2721 | - SOC_RANGES_PATH = '/proc/device-tree/soc/ranges'; | |
2722 | - SOC_RANGES_ADDRESS_OFFSET = 4; | |
2723 | -var | |
2724 | - Ranges: Integer; | |
2725 | - Buffer: array [0..3] of Byte; | |
2726 | -begin | |
2727 | - Buffer[0] := 0; | |
2728 | - Buffer[1] := 0; | |
2729 | - Buffer[2] := 0; | |
2730 | - Buffer[3] := 0; | |
2845 | +{ | |
2846 | +Anteriormente a função abaixo usava uma leitura direta de | |
2847 | +/proc/device-tree/soc/ranges, que retorna uma sequencia de Bytes. O significado | |
2848 | +e a quantidade destes Bytes mudou entre o Pi3 e o Pi4, mas basicamente, dentre | |
2849 | +eles, existem 3 grupos de Bytes que ficam no começo dessa sequência. Observe os | |
2850 | +dois exemplos a seguir e sua posterior explicação: | |
2731 | 2851 | |
2732 | - Ranges := FpOpen(SOC_RANGES_PATH,O_RDONLY); | |
2852 | +Pi3: 7E000000 3F000000 01000000 | |
2853 | +Pi4: 7E000000 00000000FE000000 01800000 | |
2733 | 2854 | |
2734 | - if Ranges > 0 then | |
2735 | - try | |
2736 | - FpLseek(Ranges,SOC_RANGES_ADDRESS_OFFSET,SEEK_SET); | |
2737 | - if FpRead(Ranges,Buffer,SizeOf(Buffer)) = SizeOf(Buffer) then | |
2738 | - ABaseAdddress := Buffer[0] shl 24 or Buffer[1] shl 16 or Buffer[2] shl 8 or Buffer[3] shl 0; | |
2855 | +> Os primeiros quatro Bytes (32 bits) em todas as versões de Pi representam o | |
2856 | + "endereço-base dos periféricos do barramento do CPU VideoCore", tal como | |
2857 | + descrito no datasheet do BCM2835 e cujo valor é $7E000000. Este endereço é | |
2858 | + mapeado para o endereço-base dos periféricos (vistos a seguir), os quais são | |
2859 | + os endereços acessíveis por meio das bilbiotecas que acessam os periféricos do | |
2860 | + Pi | |
2861 | +> No Pi3, os próximos quatro Bytes (32 bits) representam o endereço-base dos | |
2862 | + periféricos que pode ser usado para mapeamento da memória para acesso aos | |
2863 | + periféricos do Pi. Neste Pi, o valor é $3F000000 | |
2864 | +> No Pi4, os próximos oito Bytes (64 bits) representam o endereço-base dos | |
2865 | + periféricos que pode ser usado para mapeamento da memória para acesso aos | |
2866 | + periféricos do Pi. Neste Pi, o valor é $00000000FE000000 (ou $FE000000) | |
2867 | +> Os próximos quatro Bytes (32 bits) em todas as versões de Pi representam o | |
2868 | + tamanho em Bytes da memória ocupada pelo mapeamento dos periféricos. No Pi3 | |
2869 | + esse valor é $01000000 e no Pi4 esse valor é $01800000 | |
2870 | +> Todas estas explicações, principalmente o tamanho de cada grupo de Bytes, foi | |
2871 | + obtida por meio de "pescaria" de informaçes na web, isto é, não achei um site | |
2872 | + que explicasse o formato de /proc/device-tree/soc/ranges, só achei pessoas | |
2873 | + falando a respeito, mas sem citar qualquer fonte | |
2739 | 2874 | |
2740 | - FpLseek(Ranges,8,SEEK_SET); | |
2741 | - if FpRead(Ranges,Buffer,SizeOf(Buffer)) = SizeOf(Buffer) then | |
2742 | - ASize := Buffer[0] shl 24 or Buffer[1] shl 16 or Buffer[2] shl 8 or Buffer[3] shl 0; | |
2743 | - finally | |
2744 | - FpClose(Ranges); | |
2745 | - end | |
2746 | - else | |
2747 | - raise EPasRipherals.Create('Não foi possível obter o endereço-base dos periféricos'); | |
2875 | +Observando a saída de sudo cat /proc/iomem podemos ver que algumas saídas | |
2876 | +mostram o resultado do mapeamento de alguns periféricos, por exemplo, para o | |
2877 | +GPIO no Pi4 há a seguinte linha: | |
2878 | + | |
2879 | +fe200000.gpio gpio@7e200000 | |
2880 | + | |
2881 | +Essa linha deve ser lida da seguinte forma: | |
2882 | + | |
2883 | +"O GPIO está acessível no endereço $FE200000, o qual mapeia (ou aponta) para o | |
2884 | +endereço $7E200000 do CPU VideoCore" | |
2885 | + | |
2886 | +No caso do GPIO, $200000, que foi somado a $7E000000 e $FE000000, é o offset, | |
2887 | +dentro do mapeamento dos periféricos, onde se encontra o GPIO. Os datasheets | |
2888 | +BCM2711 e BCM2835 mostram que o endereço do GPIO é $7E200000, porém o endereço | |
2889 | +que se deve usar ao acessar o GPIO deve ser o endereço mapeado, o qual é obtido | |
2890 | +a partir da função abaixo. Para mais informações sobre VideoCore, BCM e ARM, | |
2891 | +acesse https://en.wikipedia.org/wiki/VideoCore | |
2892 | + | |
2893 | +Outra curiosidade a respeito do VideoCore é que ele é a GPU e no Pi é a GPU que | |
2894 | +é inicializada antes do ARM, e talvez por isso que todo esse mapeamento seja | |
2895 | +necessário. Leia isso aqui: https://bootlin.com/blog/enabling-new-hardware-on-raspberry-pi-with-device-tree-overlays/ | |
2896 | +} | |
2897 | + | |
2898 | +procedure TCustomPasRipherals.PeripheralsBaseAddressAndSize(out ABaseAdddress: UInt32; out ASize: UInt32); | |
2899 | +begin | |
2900 | + ABaseAdddress := bcm_host_get_peripheral_address; | |
2901 | + ASize := bcm_host_get_peripheral_size; | |
2748 | 2902 | end; |
2749 | 2903 | |
2750 | 2904 | function TCustomPasRipherals.GPIOBaseAddress: PUInt32; |