|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Has anyone done any work with the AS3935 lightning sensor?? |
Posted: Fri Jul 14, 2017 4:17 pm |
|
|
Hi all,
I just started working on a project for myself just out of curiosity. A few months back I happen to find a module from Mikroelektronika called the thunder click that contains the AS3935 lightning sensor from Austrian Micro Systems.
I purchased one of these and started writing code for it using a PIC24. I have written most of the code for the AS3935 using a PIC24 platform. I have ported some of the code from a working example of a Mikroelektronika PIC32 application which I have modified and works quite well with their lightning board.
So far my code runs with the AS3935 and I am able to write and read the registers on the AS3935 with no problems, however I do have a problem that when I execute my code. The AS3935 goes through the initialization routines and then when the first lightning interrupt that comes out of the AS3935 which goes from low to high just stays high continuously and every now and then it does some toggling but it seems to always idle high which I do not believe is a normal condition.
I truly believe that this issue has got something to do with my driver code because this same module works perfectly on my Mikroelektronika demo board using their PIC32 code. I have not posted my code, but if anyone here has worked with this device and has some familiarity with it I would appreciate any help. Unfortunately the manufacturer of the chip does not give you much info other than data sheets and getting help from them is kind of difficult |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Fri Jul 14, 2017 4:46 pm |
|
|
Just some general comments...
Hardware: have you the correct VDD( 3V , I assume), rock stable, bypass caps, etc.....
Software: Since you've ported the code .... what about PIC clock speed? If not same there may be some 'timing' issues to deal with. SPI interface ? If so, check for correct CS levels, data stream, etc.
Assuming an IRQ for a strike... got the proper pullup in the IRQ line ?
Silly things... any other peripherals 'attached' to the I/O pins used for the sensor? Maybe a comparator, ADC, etc.?? ALL peripherals NOT used on an I/O pin should be disabled...
Jay |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
AS3935 |
Posted: Fri Jul 14, 2017 6:26 pm |
|
|
Thank you for your response.
And to answer your question or suggestion; YES, I did have another IO pin, actually the interrupt pin being shared with one of the pins on the LCD display and I fixed that and have checked it various times to make sure there are no more IO conflicts...but you are right that is probably one of the most obvious issues that would cause this. So far I have not identified it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sat Jul 15, 2017 12:16 am |
|
|
Are you reading the interrupt register?.
When the interrupt occurs, you are required to read the interrupt register, to determine what type of interrupt has happened. You need to do this even if you have it masked to only respond to the lightning event. It is the read of the register that resets the internal interrupt logic. There has to be a pause of >2mSec after the trigger before the read. An early read can cause problems. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
AS3935 |
Posted: Sat Jul 15, 2017 6:07 am |
|
|
Yes, whenever an interrupt occurs I read the interrupt register contents.
I have decided to just post my code and maybe someone may see something that may be causing the problem.
NOTE: I originally translated this code to work with a PIC18F45K22 but then moved it to a PIC24 development board, so I kept things like int8 and int16
Code: | /////////////////// the header file ////////////////////////////////////
#include <24HJ128GP502.h>
#device ICD=TRUE
#device ICSP=1
#use delay(crystal=8000000,restart_wdt)
#FUSES NOWDT, WPRES32, WPOSTS10, CKSFSM, NOJTAG
#pin_select IC1=PIN_C5 //Input capture1
#pin_select SDO1=PIN_B9 //MOSI
#pin_select SCK1OUT=PIN_B8 //CLK
#pin_select SDI1=PIN_B10 //MISO
#use spi(MASTER, FORCE_HW, SPI1, MODE=1, BITS=8)
#define THUNDER_CS PIN_B15
#define THUNDER_LED PIN_B14
#define SELECT_SW PIN_B13 |
Code: |
/////////////// the main file /////////////////////////
#include <lightning2.h>
#include <FlexLCD_Easy24-33.c>
#include <AS3935.c>
#USE FAST_IO (b)
#ZERO_RAM
//int1 InterruptFlag = 0;
#INT_EXT0
void ext0_isr(void) ///pin RB7
{
InterruptFlag = 1;
}
#INT_IC1
void ic1_isr(void)
{
// not using so far
}
#INT_TIMER1
void timer1_isr(void)
{
// not using so far
}
void Init(void)
{
set_tris_a(0xff13);
set_tris_b(0x2480);
output_high(THUNDER_CS);
output_low(THUNDER_LED);
//setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //131 ms overflow
enable_interrupts(INT_TIMER1);
ext_int_edge( L_TO_H ); // rising edge interrupt mode
setup_capture(1, CAPTURE_RE | INTERRUPT_FOURTH_CAPTURE | CAPTURE_TIMER2); // not using so far
//enable_interrupts(INT_EXT0);
//enable_interrupts(INT_IC1);
//enable_interrupts(INT_TIMER1);
enable_interrupts(INTR_GLOBAL);
}
void main()
{ unsigned int8 value,i; // dummy test variables for debug
Init();
lcd_init();
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Lightning sensor");
lcd_gotoxy(1,2);
printf(lcd_putc,"by C Barberis");
delay_ms(5000);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
Thunder_Init();
enable_interrupts(INT_EXT0);
InterruptFlag = 0;
while(1){
if (!InterruptFlag ){ // nothing happens in otherwords no interrupts
lcd_gotoxy(1,1);
printf(lcd_putc,"Waiting......");
lcd_gotoxy(1,2);
printf(lcd_putc,"#Strikes = %lu",Total_Lightings_Detected);
delay_ms(150); }
else {
// We read the AS3935 registers to see what caused the interrupt
delay_ms(2); // 2ms delay between interrupt and reading of register 0x03
// Time to read the 0x03 register which stores interupt codes
interrupt_source = Thunder_Read(0x03) & 0x0F;
delay_ms(2);
switch (interrupt_source) {
case 1: //noise
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"just noise");
delay_ms(2000);
break;
case 4: //disturber
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Disturbers");
delay_ms(2000);
break;
case 8: // is lightning
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Lightning");
Total_Lightings_Detected++;
if(Total_Lightings_Detected > 100)
Total_Lightings_Detected =0;
// now we get the distance to the lightning event
tmp1 = Thunder_Read_distance();
lcd_gotoxy(1,2);
printf(lcd_putc,"Dist = %u Km", tmp1);
output_high(THUNDER_LED);
InterruptFlag = 0;
Delay_ms(3000);
output_low(THUNDER_LED);
break; }
InterruptFlag = 0;
}
if(!input(SELECT_SW) ) // push button to read various registers
ReadInternalData();
}
} |
Code: |
//////////////////////////////// the AS3935 file ///////////////////////////////
// register access macros - register address, bitmask [ NOT Currently using these ]
#define AS3935_AFE_GB 0x00, 0x3E
#define AS3935_PWD 0x00, 0x01
#define AS3935_NF_LEV 0x01, 0x70
#define AS3935_WDTH 0x01, 0x0F
#define AS3935_CL_STAT 0x02, 0x40
#define AS3935_MIN_NUM_LIGH 0x02, 0x30
#define AS3935_SREJ 0x02, 0x0F
#define AS3935_LCO_FDIV 0x03, 0xC0
#define AS3935_MASK_DIST 0x03, 0x20
#define AS3935_INT 0x03, 0x0F
#define AS3935_DISTANCE 0x07, 0x3F
#define AS3935_DISP_LCO 0x08, 0x80
#define AS3935_DISP_SRCO 0x08, 0x40
#define AS3935_DISP_TRCO 0x08, 0x20
#define AS3935_TUN_CAP 0x08, 0x0F
// other constants
#define INDOOR 0x12
#define OUTDOOR 0x0E
unsigned int8 tmp1;
int32 tmp2;
int16 message_count = 0;
int16 Total_Lightings_Detected = 0;
int1 InterruptFlag = 0;
unsigned int8 interrupt_source, buffer;
char i;
//Func protos
void Thunder_Init(void);
void Thunder_Write(unsigned int8 address, unsigned int8 data1);
unsigned int8 Thunder_Read(unsigned int8 address);
int32 Thunder_Read_Energy(void);
unsigned int16 Thunder_Read_distance(void);
void ReadInternalData(void);
/*******************************************************************************
* Function Thunder_Init()
*
* These are the same functions from the PIC32 example from Mikroe which works fine
* ------------------------------------------------------------------------------
* Overview: Function Initializes Thunder chip
* Input: register address, data
* Output: Nothing
*******************************************************************************/
void Thunder_Init() {
unsigned int8 temp;
output_high(THUNDER_CS); // Set CS to idle
Thunder_Write(0x3C, 0x96); // set all registers in default mode
delay_ms(3);
Thunder_Write(0x3D, 0x96); // calibrate internal oscillator
delay_ms(3);
temp = Thunder_Read(0x00) & 0xC1;
delay_ms(3);
Thunder_Write(0x00, ((INDOOR << 1) | temp)); // set to indoor
delay_ms(3);
temp = Thunder_Read(0x01) & 0x80;
delay_ms(3);
Thunder_Write(0x01, 0x22 | temp); // set NFL and WDTreshold 0x44
delay_ms(3);
temp = Thunder_Read(0x02) & 0x80; // clear statistics, min number of ligtning, spike rejection
delay_ms(3);
Thunder_Write(0x02, 0xD2);
delay_ms(3);
temp = Thunder_Read(0x03) & 0x1F; // Frequency division ratio(antenna),mask disturber, interrupt
delay_ms(3);
Thunder_Write(0x03, 0x00 | temp);
delay_ms(3);
Thunder_Write(0x08, 0x00); // LCO, SRCO, TRCO on IRQ, capacitors tuning
delay_ms(1000);
}
/*******************************************************************************
* Function Thunder_Write(unsigned short address, unsigned short data1)
* ------------------------------------------------------------------------------
* Overview: Function writes desired byte into specified register address
* Input: register address, byte
* Output: Nothing
*******************************************************************************/
void Thunder_Write(unsigned int8 address, unsigned int8 data1) {
bit_clear(address,7); // set both bits 6&7 to 0 to do a write
bit_clear(address,6);
output_low(THUNDER_CS);
spi_xfer(address); // spi_write(address);
spi_xfer(data1); // spi_write(data1);
output_high(THUNDER_CS);
}
/*******************************************************************************
* Function Thunder_Read(unsigned short address)
* ------------------------------------------------------------------------------
* Overview: Function reads byte from specified address
* Input: register address
* Output: desired byte
*******************************************************************************/
unsigned int8 Thunder_Read(unsigned int8 address) {
unsigned int8 tmp = 0;
bit_clear(address,7); // set both bits 7 =0 and bit 6 = 1 to do a read
bit_set(address,6);
output_low(THUNDER_CS);
spi_xfer(address); //spi_write(address);
tmp = spi_xfer(0); // spi read data;
output_high(THUNDER_CS);
return tmp;
}
/*******************************************************************************
* Function Thunder_Read_Energy()
* ------------------------------------------------------------------------------
* Overview: Function reads energy of detected thunder
* Input: Nothing
* Output: Measured result
*******************************************************************************/
int32 Thunder_Read_Energy() {
unsigned int8 low_byte, mid_byte;
int32 Out_thunder_energy;
Out_thunder_energy = Thunder_Read(0x06) & 0x1F;
mid_byte = Thunder_Read(0x05);
low_byte = Thunder_Read(0x04);
Out_thunder_energy = (Out_thunder_energy << 8);
Out_thunder_energy = (Out_thunder_energy | mid_byte);
Out_thunder_energy = (Out_thunder_energy << 8);
Out_thunder_energy = (Out_thunder_energy | low_byte);
return Out_thunder_energy;
}
/*******************************************************************************
* Function Thunder_Read_distance()
* ------------------------------------------------------------------------------
* Overview: Function reads distance from detected thunder
* Input: Nothing
* Output: Measured result
*******************************************************************************/
unsigned int16 Thunder_Read_distance() {
int16 Out_thunder_distance;
Out_thunder_distance = Thunder_Read(0x07) & 0x3F;
return Out_thunder_distance;
}
/////////////////////////////////// Routines to read internal registers ///////////////////////////
void ReadInternalData() {
unsigned int test1, test2,i;
tmp1 = Thunder_Read(0x00) & 0x20;
delay_ms(10);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Disturbers");
lcd_gotoxy(1,2);
if(tmp1 == 0x20)
printf(lcd_putc,"Enabled");
else
printf(lcd_putc,"Disabled");
delay_ms(5000);
tmp1 = Thunder_Read(0x00) & 0x3E;
tmp1 = tmp1 >> 1;
delay_ms(10);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Sensor set to:");
lcd_gotoxy(1,2);
if(tmp1 == INDOOR)
printf(lcd_putc,"Indoor mode");
else if(tmp1 == OUTDOOR )
printf(lcd_putc,"Outdoor mode");
//printf(lcd_putc," = %u", tmp1);
delay_ms(5000);
tmp1 = Thunder_Read(0x01) & 0x70;
delay_ms(10);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Noise Level:");
lcd_gotoxy(1,2);
printf(lcd_putc," = %u", tmp1);
delay_ms(5000);
tmp1 = Thunder_Read(0x01) & 0x0F;
delay_ms(10);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"WatchDog set to:");
lcd_gotoxy(1,2);
printf(lcd_putc," = %u", tmp1);
delay_ms(5000);
tmp1 = Thunder_Read(0x02) & 0x0F;
delay_ms(10);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"Spike Rejection:");
lcd_gotoxy(1,2);
printf(lcd_putc," = %u", tmp1);
delay_ms(5000);
lcd_putc("\f"); // Clear display
lcd_gotoxy(1,1);
printf(lcd_putc,"All done");
lcd_gotoxy(1,2);
printf(lcd_putc,"Reading registers");
delay_ms(4000);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sat Jul 15, 2017 8:39 am |
|
|
First thing, you should specify a clock rate.
On these chips you have a programmable PLL. So you need CRYSTAL=8MHz, CLOCK=xxMHz where the second figure is what you want the PLL programmed to give. Then (this may well be the problem), you need to specify the SPI rate (BAUD=2000000). The chip supports a maximum SPI rate of 2Mhz. Even at 8Mhz, your new PIC is capable of clocking the SPI at 4MHz, and the default unless you specify a clock rate, is always as fast as possible.... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Sat Jul 15, 2017 10:21 am |
|
|
I see another problem.
When you are sending values, and then raising the CS after the send, you need to code as:
Code: |
void Thunder_Write(unsigned int8 address, unsigned int8 data1) {
int8 dummy;
bit_clear(address,7); // set both bits 6&7 to 0 to do a write
bit_clear(address,6);
output_low(THUNDER_CS);
spi_xfer(address); // spi_write(address);
dummy=spi_xfer(data1); // spi_write(data1);
output_high(THUNDER_CS);
}
|
Adding the read here, ensures the transfer completes before you raise CS. Otherwise the line will go up while the data is still sending. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Sat Jul 15, 2017 1:42 pm |
|
|
I only want to use the crystal at 8.00MHz not really interested in using the PLL so that is why I left just the crystal figure
I'm I supposed to use CRYSTAL=8MHz, CLOCK=8MHz ??
As far as the SPI writes and reads, I monitored all the MISO and MOSI traffic on my logic analyzer and there is ~ 20 uS from the last data bit transferred to the point where the CS line gets raised. Also Every value I write to any register I am able to read later, so the SPI data transfer seems to work fine. The thing that I noticed is that my interrupt output from my AS3935 once it goes high it stays high something that the other system (PIC32) does not do, that line stays low and transitions high for about 50uS then it goes low until the next interrupt happens. In this case this is not working correctly because on the first interrupt the line goes high and stays high forever until I do a read of the interrupt status register, it then goes low for a short period and back to high again and stays there. Definitely something stupid that I am doing. I have checked all the working registers and they appear to have the correct values? ...so I am lost. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Jul 19, 2017 2:57 am |
|
|
Yes. On the PLL, the problem is that a lot of components like this _must_ be configured. Can't just be ignored. Setting CRYSTAL=8MHz, CLOCK=8MHz, ensures the compiler sets it up to disable the PLL.
Beware on looking at the CS with the scope. The transaction _will_ be correct on all 'read' transfers (since these use tmp = spi_xfer(0) for the second transfer). It is only on the last byte of a write transfer that the dummy is needed. So only on the transfer at the end of the Thunder_write. You may be missing this being wrong... :(
This could easily cause some errors.
The line staying high, is saying that the interrupt has not been cleared. So something is preventing this. Question is what.... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|