Se vocês perderam algum dos posts anteriores, podem acessá-los pela lista abaixo:
1- MiWi: Dispositivos e topologias de rede;
2- MiWi: Endereçamento;
3- MiWi: Relatórios de protocolo;
4- MiWi: Mensagens de Stack e Serviços
5- MiWi: Segurança
Como a biblioteca da Microchip para o MiWi foi desenvolvida recentemente, há ainda alguns bugs e também muitas atualizações. Ela é fornecida com o Microchip Application Libraries, e a última versão disponível agora, enquanto escrevo este artigo, é a versão de junho de 2011 (Stack MiWi 4.2). Quem estiver com sua versão desatualizada, é bom atualizar.
Hardware do projeto
Desenhamos o circuito do projeto no KiCad, que pode ser visto abaixo:Criamos o componente MRF24J40MA, já que o KiCad não o possui. Você poderá obter todos os datasheets relacionados a este módulo no site da Microchip.
O módulo MRF24J40MA é o módulo que fará todo o trabalho de transmissão e recepção de pacotes. Você o controla via barramento SPI. Ele na verdade é um transceiver feito pela Microchip para os protocolos ZigBee ou MiWi... Mas como um transceiver, você poderá criar qualquer protocolo de comunicação com ele. O Stack MiWi não está no módulo, mas é implementado pelas bibliotecas da Microchip.
Para você ter uma visão geral dos registradores disponíveis deste módulo, procure pelo datasheet do circuito integrado principal dele, o MRF24J40. Há ainda uma versão deste módulo de maior alcance, chamado de MRF24J40MB.
A alimentação do módulo é de 3.3V. Para simplificar o desenho acima, não incluímos a fonte. Portanto, quando você for implementar este projeto, lembre-se de incluí-la.
Incluindo os arquivos do projeto
Vamos agora ao PCAD, e vamos criar um novo projeto com PICF4550. Os arquivos que devemos incluir são os arquivos abaixo:Arquivo | Pasta |
---|---|
Console.c | \Microchip Solutions\Microchip\WirelessProtocols\ |
MSPI.c | \Microchip Solutions\Microchip\WirelessProtocols\ |
SymbolTime.c | \Microchip Solutions\Microchip\WirelessProtocols\ |
MiWi.c | \Microchip Solutions\Microchip\WirelessProtocols\MiWi\ |
MRF24J40.c | \Microchip Solutions\Microchip\Transceivers\MRF24J40\ |
MiWi.c | \Microchip Solutions\Microchip\WirelessProtocols\MiWi\ |
Os cabeçalhos relacionados com estes arquivos podem ser adicionados para facilitar a visualização. Por fim, devemos copiar três arquivos que serão necessários para o projeto: ConfigApp.h, HardwareProfile.h, SystemProfile.h. Para o projeto de um dispositivo End Device, nós vamos copiar estes arquivos do diretório Microchip Solutions\MiWi DE Demos\Node 2. Para Coordinators, devemos copiar estes arquivos do diretório Microchip Solutions\MiWi DE Demos\Node 1. São eles que conterão as configurações de rede do projeto, bem como o esquema de ligação deste projeto.
Assim que copiar estes arquivos para a pasta do projeto, inclua-os. Fazendo isto, vamos editar o arquivo HardwareProfile.h, para que ele reflita o nosso esquemático:
#ifndef _HARDWARE_PROFILE_H #define _HARDWARE_PROFILE_H #include "GenericTypeDefs.h" #include "ConfigApp.h" #include <p18cxxx.h> #define CLOCK_FREQ 48000000 #define RFIF INTCON3bits.INT2IF #define RFIE INTCON3bits.INT2IE #define PHY_CS LATCbits.LATC2 #define PHY_CS_TRIS TRISCbits.TRISC2 #define RF_INT_PIN PORTBbits.RB2 #define RF_INT_TRIS TRISBbits.TRISB2 #define SPI_SDI PORTBbits.RB0 #define SDI_TRIS TRISBbits.TRISB0 #define SPI_SDO LATCbits.LATC7 #define SDO_TRIS TRISCbits.TRISC7 #define SPI_SCK LATBbits.LATB1 #define SCK_TRIS TRICBbits.TRISB1 #define PHY_RESETn LATCbits.LATC0 #define PHY_RESETn_TRIS TRISCbits.TRISC0 #define PHY_WAKE LATCbits.LATC1 #define PHY_WAKE_TRIS TRISCbits.TRISC1 #define LED_1 PORTEbits.RE0 #define LED_1_TRIS TRISEbits.TRISE0 #define LED_2 PORTEbits.RE1 #define LED_2_TRIS TRISEbits.TRISE1 #define LED_3 PORTEbits.RE2 #define LED_3_TRIS TRISEbits.TRISE2 #define TMRL TMR0L #define TOOGLE(c) c = ~c #endifAqui nós definimos todas as ligações feitas com o módulo MRF24J40MA. Se alguma destas definições faltar, o compilador gerará erros. O clock e o registrador do timer usado também devem ser definidos aqui, para que o Stack MiWi possa fazer as temporizações corretamente. Portanto, você não poderá usar este timer.
Configurando o projeto
A configuração do projeto é feita no arquivo ConfigApp.h. Veja quais opções você poderá selecionar neste arquivo:Configuração | Descrição |
---|---|
ENABLE_CONSOLE | Habilita a impressão de mensagens pela serial do microcontrolador. Comente esta definição, para desabilitá-la. |
SIMPLE_EXAMPLE | Desabilita todas as funções mais avançadas do Stack. Insira esta definição no projeto, para habilitá-la. |
ENABLE_NETWORK_FREEZER | Grava todos os dados mais importantes de uma conexão em memória não volátil, para rápido restabelecimento da rede. É necessário ter esta memória no projeto. |
HARDWARE_SPI | Utiliza o módulo SPI nativo do microcontrolador para comunicação. Comentando-se esta definição, o Stack tentará emular uma SPI. Recomendável usar o SPI nativo. |
PROTOCOL_P2P | Habilita a rede P2P. Não pode ser definido juntamente com PROTOCOL_MIWI |
PROTOCOL_MIWI | Habilita a rede MiWi Mesh. Não pode ser definido juntamente com PROTOCOL_P2P |
NWK_ROLE_COORDINATOR | Define o dispositivo como Coordinator. Não pode ser definido juntamente com NWK_ROLE_END_DEVICE. |
NWK_ROLE_END_DEVICE | Define o dispositivo como End Device. Não pode ser definido juntamente com NWK_ROLE_COORDINATOR. |
MRF24J40 | Define que o módulo MRF24J40MA de 2.4GHz será usado. Não pode ser definido junto com outros transceivers. |
MRF49XA | Define que o módulo subGHz MRF49XA da Microchip será usado. Não pode ser definido junto com outros transceivers. |
MRF89XA | Define que o módulo subGHz MRF89XA da Microchip será usado. Não pode ser definido junto com outros transceivers. |
MY_ADDRESS_LENGTH | Define o tamanho do endereço permanente do nó, em bytes. |
EUI_0 - EUI_7 | Esta é a definição do endereço EUI do módulo. Cada dígito é um byte do endereço. |
TX_BUFFER_SIZE | Define o tamanho do buffer de transmissão. |
RX_BUFFER_SIZE | Define o tamanho do buffer de recepção. |
MY_PAN_ID | Define o PANID do dispositivo. |
ADDITIONAL_NODE_ID_SIZE | Define o tamanho dos dados adicionais que serão anexados à requisição P2P. Estas são informações que os dispositivos querem compartilhar com outros pontos na conexão. Estes dados serão definidos pela aplicação. |
CONNECTION_SIZE | Define o máximo de conexões P2P que este dispositivo permite ao mesmo tempo. |
TARGET_SMALL | Remove algumas funcionalidades para diminuir o código gerado. |
ENABLE_PA_LNA | Habilita o amplificador de potência em transceivers que o possuem. |
ENABLE_HAND_SHAKE | Habilita o hand-shake antes da comunicação. Sem isto, os transceivers RF só poderão fazer broadcast, ou possuir o endereço de destino programado no firmware para comunicação com um dispositivo. |
ENABLE_SLEEP | Permite que o dispositivo vá para o modo sleep e volte dele. |
ENABLE_ED_SCAN | Habilita a detecção de energia, para descobrir qual o canal que possui menos ruído. |
ENABLE_ACTIVE_SCAN | Habilita o Active Scan, para detectar as conexões atualmente existentes. |
ENABLE_SECURITY | Habilita a encriptação de dados na transmissão. |
ENABLE_INDIRECT_MESSAGE | Fará com que o dispositivo guarde mensagens para dispositivos que estão em modo sleep, até que eles retornem ao funcionamento normal. |
ENABLE_BROADCAST | Fará com que o dispositivo envie broadcasts aos dispositivos em modo sleep, até que eles retornem ao funcionamento normal. |
RFD_WAKEUP_INTERVAL | Define o intervalo de wakeup para dispositivos RFD em segundos. Esta definição no entanto não é utilizada pelos dispositivos RFD, mas pelos dispositivos FFD, para calcular seus vários timeouts. |
ENABLE_FREQUENCY_AGILITY | Faz com que o dispositivo possa mudar de canal, quando houver uma súbita mudança no ruído. |
Arquivo principal do projeto
No arquivo principal, você precisará definir algumas coisas também. Vamos ao esqueleto básico deste arquivo:#include <stdio.h> #include "GenericTypeDefs.h" #include "Compiler.h" #include "WirelessProtocols/MSPI.h" #include "WirelessProtocols/MCHP_API.h" #include "HardwareProfile.h" #if ADDITIONAL_NODE_ID_SIZE > 0 BYTE AdditionalNodeID[ADDITIONAL_NODE_ID_SIZE] = {0x01}; #endif BYTE myChannel = 11; #pragma config FOSC=HSPLL_HS #pragma config CPUDIV=OSC1_PLL2 #pragma config PLLDIV=5 #pragma config USBDIV=2 #pragma config CCP2MX=ON #pragma config WDT=OFF #pragma config WDTPS=32768 #pragma config MCLRE=ON #pragma config LVP=OFF #pragma config VREGEN=ON #pragma config IESO=OFF #pragma config PWRT=ON #pragma config BOR=OFF #pragma config CP0=OFF #pragma config CP1=OFF #pragma config CP2=OFF #pragma config CP3=OFF #pragma config CPB=OFF #pragma config CPD=OFF #pragma config WRT0=OFF #pragma config WRT1=OFF #pragma config WRT2=OFF #pragma config WRT3=OFF #pragma config WRTB=OFF #pragma config WRTC=OFF #pragma config WRTD=OFF #pragma config EBTR0=OFF #pragma config EBTR1=OFF #pragma config EBTR2=OFF #pragma config EBTR3=OFF #pragma config EBTRB=OFF #pragma config DEBUG=ON #pragma config XINST=ON void UserInterruptHandler(void) { } void main(void) { BYTE i=0xFF; RCON = 0x80; // Habilita prioridades para interrupções ADCON0 = 0x00; ADCON1 = 0x0F; // PORTA só como entradas e saídas digitais. CMCON = 0x07; // Comparadores desligados. TRISA = 0xFF; TRISB = 0x05; TRISC = 0x00; PORTC = 0x06; TRISD = 0x00; PORTD = 0x00; TRISE = 0x07; PORTE = 0xFF; INTCON = 0x00; INTCON2 = 0x00; INTCON3 = 0x00; // Configura o módulo SPI SSPSTAT = 0xC0; SSPCON1 = 0x20; INTCONbits.GIEH = 1; RFIF = 0; // Limpa o interrupt flag do chip. RFIE = 1; INTCON2bits.INTEDG2 = 0; MiApp_ProtocolInit(FALSE); if(MiApp_SetChannel(myChannel) == FALSE) { return; } MiApp_ConnectionMode(ENABLE_ALL_CONN); while((i = MiApp_EstablishConnection(0xFF, CONN_MODE_DIRECT)) == 0xFF); #ifdef ENABLE_DUMP DumpConnection(0xFF); #endif LED_2 = 1; for(;;) { if(MiApp_MessageAvailable()) { // Aqui tratamos a mensagem recebida. MiApp_DiscardMessage(); } } }O código acima é de um arquivo prinpipal para o projeto de dispositivo End Device. A diferença entre o End Device e o Coordinator é apenas a função main. Duas definições devem ser feitas no arquivo principal. A primeira é a definição da variável AdditionalNodeID, conforme pode ser visto acima. Os arquivos do Stack MiWi usam esta variável, portanto é necessário pelo menos definí-la. A segunda definição é a da função UserInterruptHandler. Esta função é chamada depois que a interrupção do MiWi for executada, e precisa também ser declarada, mesmo que nada seja feito ali.
Além destas declarações, você deverá ainda configurar o módulo SPI e habilitar a interrupção que você definiu para o módulo MRF24J40MA (o Stack não faz isto como acontece em outras bibliotecas Microchip). Feito isto, seu projeto está pronto para funcionar.
As diferenças existentes neste arquivo acima, para o projeto do Coordinator são poucas. Compare com o código abaixo (do Coordinator):
MiApp_ProtocolInit(FALSE); if(MiApp_SetChannel(myChannel) == FALSE) { return; } MiApp_ConnectionMode(ENABLE_ALL_CONN); MiApp_StartConnection(START_CONN_DIRECT, 10, 0); #ifdef ENABLE_DUMP DumpConnection(0xFF); #endif LED_2 = 1; for(;;) { if(MiApp_MessageAvailable()) { MiApp_DiscardMessage(); } }Pode-se observar que o End Device usa a função MiApp_EstablishConnection, enquanto o Coordinator usa a função MiApp_StartConnection. Esta função inicializa a rede MiWi, e somente com uma rede estabelecida, é que os dispositivos End Device podem estabelecer conexões.