Interfacing PCA9955 I2C LED driver - avr

I want to interface ATmega128 to PCA9955 LED driver using TWi communication mode. The TWI is ok but even so the PCA9955 doesn't acknowledge it. I am trying to light up LED 14 without using PWM. My code is here. I have connected AD0, AD1 and AD2 pins of PCA9955 to ground so address is device address is 0x02. Can anyone tell me what did I miss here regarding PCA9955 LED driver ?
void master_twi_init(void)
{
TWSR = 0x03;
TWBR = 124; // SCl frequency 1000Hz (approximately)
}
void device_init(void)
{
stdout = &uart0_str;
uart0_init();
master_twi_init();
}
int main(void){
device_init();
_delay_ms(5);
twi_tx_byte(0x05, 0b00010000); // Set LED 14 fully bright
while(1){;}
}
void twi_tx_byte(uint8_t addr, uint8_t data)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(0<<TWSTO)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x08){printf("Start error.\r\n");}
_delay_ms(100);
TWDR = 0xC0; //For now all addresses are connected to ground
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x18){printf("device ack err.\r\n");}
_delay_ms(100);
TWDR = addr;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x28){printf("address ack err.\r\n");}
_delay_ms(100);
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x28){printf("data ack err.\r\n");}
_delay_ms(100);
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}
The output I get is.
device ack err.
address ack err.
data ack err.
The only thing that is okay is 'Start' of I2C.
This is my circuit.

According to this datasheet, the 9955 has 4 address pins. You need to pull A3 low or high, too.
But even then, the address is not 0x02. In Fig.3 in section 7.1.1, the address is shown to be
1 1 0 A3 A2 A1 A0 R/W
So if you ground all the pins, the device address should be 0xC0 or 0xC1, depending on whether you are reading or writing to it.

Related

SPI implementation stuck on “while(!spi_is_tx_empty(WINC1500_SPI));”

I'm currently implementing a driver for the WINC1500 to be used with an ATMEGA32 MCU and it's getting stuck on this line of "while(!spi_is_tx_empty(WINC1500_SPI));". The code builds and runs but it won't clear what's inside in this function to proceed through my code and boot up the Wifi Module. I've been stuck on this problem for weeks now with no progress and don't know how to clear it.
static inline bool spi_is_tx_empty(volatile avr32_spi_t *spi)
{
// 1 = All Transmissions complete
// 0 = Transmissions not complete
return (spi->sr & AVR32_SPI_SR_TXEMPTY_MASK) != 0;
}
Here is my implementation of the SPI Tx/Rx function
void m2mStub_SpiTxRx(uint8_t *p_txBuf,
uint16_t txLen,
uint8_t *p_rxBuf,
uint16_t rxLen)
{
uint16_t byteCount;
uint16_t i;
uint16_t data;
// Calculate the number of clock cycles necessary, this implies a full-duplex SPI.
byteCount = (txLen >= rxLen) ? txLen : rxLen;
// Read / Transmit.
for (i = 0; i < byteCount; ++i)
{
// Wait for transmitter to be ready.
while(!spi_is_tx_ready(WINC1500_SPI));
// Transmit.
if (txLen > 0)
{
// Send data from the transmit buffer
spi_put(WINC1500_SPI, *p_txBuf++);
--txLen;
}
else
{
// No more Tx data to send, just send something to keep clock active.
// Here we clock out a don't care byte
spi_put(WINC1500_SPI, 0x00U);
// Not reading it back, not being cleared 16/1/2020
}
// Reference http://asf.atmel.com/docs/latest/avr32.components.memory.sdmmc.spi.example.evk1101/html/avr32_drivers_spi_quick_start.html
// Wait for transfer to finish, stuck on here
// Need to clear the buffer for it to be able to continue
while(!spi_is_tx_empty(WINC1500_SPI));
// Wait for transmitter to be ready again
while(!spi_is_tx_ready(WINC1500_SPI));
// Send dummy data to slave, so we can read something from it.
spi_put(WINC1500_SPI, 0x00U); // Change dummy data from 00U to 0xFF idea
// Wait for a complete transmission
while(!spi_is_tx_empty(WINC1500_SPI));
// Read or throw away data from the slave as required.
if (rxLen > 0)
{
*p_rxBuf++ = spi_get(WINC1500_SPI);
--rxLen;
}
else
{
spi_get(WINC1500_SPI);
}
}
Debug output log
Disable SPI
Init SPI module as master
Configure SPI and Clock settings
spi_enable(WINC1500_SPI)
InitStateMachine()
INIT_START_STATE
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2mStub_PinSet_CE
m2mStub_PinSet_RESET
m2mStub_GetOneMsTimer();
SetChipHardwareResetState (CHIP_HARDWARE_RESET_FIRST_DELAY_1MS)
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
if(m2m_get_elapsed_time(startTime) >= 2)
m2mStub_PinSet_CE(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_SECOND_DELAY_5_MS);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 6
m2mStub_PinSet_RESET(M2M_WIFI_PIN_HIGH)
startTime = m2mStub_GetOneMsTimer();
SetChipHardwareResetState(CHIP_HARDWARE_RESET_FINAL_DELAY);
InitStateMachine()
INIT_WAIT_FOR_CHIP_RESET_STATE
m2m_get_elapsed_time(startTime) >= 10
SetChipHardwareResetState(CHIP_HARDWARE_RESET_COMPLETE)
retVal = true // State machine has completed successfully
g_scanInProgress = false
nm_spi_init();
reg = spi_read_reg(NMI_SPI_PROTOCOL_CONFIG)
Wait for a complete transmission
Wait for transmitter to be ready
SPI_PUT(WINC1500_SPI, *p_txBuf++);
--txLen;
Wait for transfer to finish, stuck on here
Wait for transfer to finish, stuck on here
The ATmega32 is an 8-bit AVR but you seem to be using code for the AVR32, a family of 32-bit AVRs. You're probably just using the totally wrong code and you should consult the datasheet of the ATmega32, and search for SPI for the AVR ATmega family.

CAN 1 RX works in loopback mode, but not in Normal mode

I am using a STM32F413RG based custom board and trying to run some CAN bus based applications on it.
I am trying to start with CAN 1 and wrote a bare metal code using CMSIS library to transmit and receive.
Here is the code for three functions - Init,Send and Receive.
void initCAN()
{
// enable clock
// note: because CAN2 is a "slave CAN" you have to enable CAN1 clock
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
// and reset CAN1, so request reset
CAN1->MCR |= CAN_MCR_RESET;
// wait for it to say it has gone to sleep
while ((CAN1->MSR & CAN_MSR_SLAK_Msk) == 1) {}
//CAN1
// enable port A clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
__DSB();
// CAN_RX = CAN1R on PA11, so set alt function
GPIOA->MODER &= ~GPIO_MODER_MODER11_Msk;
GPIOA->MODER |= GPIO_MODER_MODER11_1;
// CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL11_3 | GPIO_AFRH_AFSEL11_0);
// CAN_TX = CAN1T on PA12
GPIOA->MODER &= ~GPIO_MODER_MODER12_Msk;
GPIOA->MODER |= GPIO_MODER_MODER12_1;
// open-drain
GPIOA->OTYPER |= GPIO_OTYPER_OT_11;
GPIOA->OTYPER |= GPIO_OTYPER_OT_12;
// CAN 1 is AF9 (AFSEL 9 = 0b1001 -> bit 3 & bit 0
GPIOA->AFR[1] |= (GPIO_AFRH_AFSEL12_3 | GPIO_AFRH_AFSEL12_0);
//bring it our from sleep by setting the sleep bit in MCR to 0
CAN1->MCR &= ~CAN_MCR_SLEEP_Msk;
//if sleep ACK(SLAK) not zero, wait i.e. exited from sleep
while ((CAN1->MSR & CAN_MSR_SLAK_Msk) != 0) {}
//put CAN 1 to Init mode
CAN1->MCR |= CAN_MCR_INRQ;
// wait for it to say it has gone there
while ((CAN1->MSR & CAN_MSR_INAK_Msk) != CAN_MSR_INAK_Msk) {}
uint32_t APB1Clock = SystemCoreClock/2000000; // in MHz
CAN1->BTR = 0x00050007U;
CAN1->FMR |= CAN_FMR_FINIT;
// and make sure the CANSB value is zero
CAN1->FMR &= ~(CAN_FMR_CAN2SB_Msk);
//Give 14 filter banks to CAN 1 and 2 each
CAN1->FMR |= (((uint32_t) 14) << CAN_FMR_CAN2SB_Pos) & CAN_FMR_CAN2SB_Msk;
// set all as 32 bit filter in identifier mask mode (zeros)
CAN1->FM1R = 0;
// use all as 32 bit filter with mask
CAN1->FS1R |= CAN_FS1R_FSC_Msk;
// assign FIFO0 to CAN1, and FIFO1 to CAN2 (well, all to FIFO0, except filter 14)
CAN1->FFA1R = CAN_FFA1R_FFA14;
// make sure it is deactivated (clear FACT in CAN_FAR)
CAN1->FA1R &= ~CAN_FA1R_FACT0;
CAN1 ->FA1R &= ~CAN_FA1R_FACT14;
// setup a filter that accepts everything (w/ extended id)
// Each filter bank i (i= 0 to 27 in dual CAN configuration and i= 0 to 13 in single CAN configuration)
//is composed of two 32-bit registers, CAN_FiR\[2:1\].
CAN1->sFilterRegister[0].FR1 = CAN_F0R1_FB2;
CAN1->sFilterRegister[0].FR2 = CAN_F0R1_FB2;
CAN1->sFilterRegister[14].FR1 = CAN_F0R1_FB2;
CAN1->sFilterRegister[14].FR2 = CAN_F0R1_FB2;
// now activate filter
CAN1->FA1R |= CAN_FA1R_FACT0;
CAN1->FA1R |= CAN_FA1R_FACT14;
// take out of init mode for filters
CAN1->FMR &= ~CAN_FMR_FINIT;
//loopback mode. need to do it while on init mode
// CAN1->BTR |= CAN_BTR_LBKM;
//bring CAN1 out from init mode.
CAN1->MCR &= ~CAN_MCR_INRQ;
while ((CAN1->MSR & CAN_MSR_INAK_Msk) != 0) {}
}
void sendCAN1( uint32_t pgn, uint8_t bytes[], uint8_t len)
{
// wait for the mailbox to be empty
while ((CAN1->TSR & CAN_TSR_TME0_Msk) == 0) {};
// put this in next empty mailbox
int boxnum = (CAN1->TSR & CAN_TSR_CODE_Msk) >> CAN_TSR_CODE_Pos;
CAN1->sTxMailBox[boxnum].TDTR &= ~CAN_TDT0R_DLC_Msk;
CAN1->sTxMailBox[0].TIR = ((pgn << CAN_TI0R_EXID_Pos) & CAN_TI0R_EXID_Msk) | CAN_TI0R_IDE;
// for standard (11-bit) ids, replace the above with:
// CAN1->sTxMailBox[boxnum].TIR = ((pgn << CAN_TI0R_STID_Pos) & CAN_TI0R_STID_Msk);
CAN1->sTxMailBox[boxnum].TDHR = ((bytes[7]<<CAN_TDH0R_DATA7_Pos) |
(bytes[6]<<CAN_TDH0R_DATA6_Pos) |
(bytes[5]<<CAN_TDH0R_DATA5_Pos) | bytes[4]);
CAN1->sTxMailBox[boxnum].TDLR = ((bytes[3]<<CAN_TDL0R_DATA3_Pos) |
(bytes[2]<<CAN_TDL0R_DATA2_Pos) |
(bytes[1]<<CAN_TDL0R_DATA1_Pos) | bytes[0]);
CAN1->sTxMailBox[boxnum].TDTR = (len << CAN_TDT0R_DLC_Pos) & CAN_TDT0R_DLC_Msk;
CAN1->sTxMailBox[boxnum].TIR |= CAN_TI0R_TXRQ;
}
uint8_t recCAN1()
{
uint8_t data[8];
uint32_t pgn;
uint8_t len;
uint8_t msgcount;
static uint8_t ret = 0;
// check for any msg in FIFO
// we only use FIFO 0 here
msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
ret += msgcount;
// read them out one at a time
while (msgcount > 0)
{
pgn = CAN1->sFIFOMailBox[0].RIR >> 3;
len = CAN1->sFIFOMailBox[0].RDTR & 0xF;
// NOTE: case fall through is intentional and critical
switch (len)
{
case 8:
data[7] = (CAN1->sFIFOMailBox[0].RDHR >> 24) & 0xFF;
case 7:
data[6] = (CAN1->sFIFOMailBox[0].RDHR >> 16) & 0xFF;
case 6:
data[5] = (CAN1->sFIFOMailBox[0].RDHR >> 8) & 0xFF;
case 5:
data[4] = CAN1->sFIFOMailBox[0].RDHR & 0xFF;
case 4:
data[3] = (CAN1->sFIFOMailBox[0].RDLR >> 24) & 0xFF;
case 3:
data[2] = (CAN1->sFIFOMailBox[0].RDLR >> 16) & 0xFF;
case 2:
data[1] = (CAN1->sFIFOMailBox[0].RDLR >> 8) & 0xFF;
case 1:
data[0] = CAN1->sFIFOMailBox[0].RDLR & 0xFF;
// do nothing as data is empty
}
// process as they are read
// processCAN(pgn, data, len);
// release that mailbox
CAN1->RF0R |= CAN_RF0R_RFOM0;
// update the message count
msgcount = CAN1->RF0R & CAN_RF0R_FMP0_Msk;
}
return ret;
}
Sending a packet from CAN 1 is fine. When receiving, I cannot see any status changing on the Rx Registers. But, I can see an ACK being transmitted from the TX pin upon receiving a packet when scoping the signals.
The CAN 1 Error Status is completely empty (0x0).
However, when I try the same code with Loopback mode activated, I can see a message received on the registers and my code picks it up too.
Attaching screenshots of CAN 1 RF0R register when in loopback mode which indicates reception.
This scope (Channel 0 for RX and Channel 2 for TX) shows that its receiving a message on RX and it sends back an ACK on its TX under normal mode.
I have checked the termination too and its fine. (120 ohms added. Anyway, getting an ACK, so I am thinking that's not the problem).
I am out of ideas of where I might be going wrong.
No explicit error messages. However, the Rx message is not reflecting on any one of the registers under normal mode.
From the reference manual in CAN_FMR register : to use CAN1 only: stop the clock on CAN2 and/or set the CAN_MCR.INRQ on CAN2, I haven't seen instruction that does this explicitly in your code.
Also in the comments from your code it says that you are not filtering anything but you set CAN_F0R1_FB2 in sFilterRegister thus not everything will be accepted. The ID you are sending is one of those.

TWI on ATMega 2560 wait's in infinity loop

I get some stupid error's if I want to try initialise the connection from the TWI master to the bus. The start condition will be send but the processor waits in the infinity loop bevor starting to send the slave address to the bus.
I also have analysed the signals on the bus and one result is that the clock is running but there will be no data send on the bus.
The processor wait's in the line with the marked arrow.
We use the following code to start the and initialise the bus ...
void i2c_master_init() {
TWBR = (uint8_t)TWBR_val;
}
void i2c_master_stop() {
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}
uint8_t i2c_master_start(uint8_t address) {
TWCR = 0;
TWCR |= (1<<TWSTA);
TWCR |= (1<<TWEN);
TWCR |= (1<<TWINT);
while( !(TWCR & (1<<TWINT)) ); <--
[...]
}
Currently I don't know, what's going wrong with the code. Or am I doing something else wrong. Can anyone help me?
Thank you in anticipation.
My best guess without hardware on my bench is that you should set all flags to TWI control registry at once by TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN). Meanwhile you set them one by one in 3 separate operations (multiple clock cycles), while datasheet implicitly says flags must be set together, see also datasheet examples.

Raspberry PI to AVR attiny26 via SPI - three wire mode, garbled output

I have Raspberry PI 3 connected via SPI to AVR Attiny26, which in turn has a LCD connected to it. I am trying to get the SPI running,
Now, the issue is that when I set up the AVR for two wire mode and don't configure pull-up on PB1 (MISO commented out):
USICR = (1<<USIOIE)|(1<<USIWM1)|(1<<USICS1); // Enable USI interrupt - USIOIE=1
// Three wire mode USIWM1=0, USIWM0=1
// Two wire mode USIWM1=1, USIWM0=0
// External clock USICS1=1
//PORTB |= (1<<SPI_MISO); // Enable pull-ups on SPI port
DDRB = 0b01001010; /* Set PORTB bits: 7-4 as input
-- PB7 - Pushbutton (KEY1)/RESET
-- PB6 - Pushbutton (KEY2)/INT0
-- PB5 - ADC8 (T2)
-- PB4 - ADC7 (T1)
-- PB3 - PUMP
-- PB2 - SCK - 0 = external clock (input)
-- PB1 - MISO (output)
-- PB0 - MOSI (input) - */
ISR(USI_OVF_vect) {
disp[counter++] = USIDR;
if(counter==16)
counter = 0;
USISR |= (1<<USIOIF);
}
I get the string transfered and printed on the LCD.
However, when I change the AVR to work in three wire mode and/or enable PB1 pull-up, all I get is garbage. Neither the received characters match the ones sent, nor does their count.
Raspberry is the master here, providing all the clocking, the setup there is always the same (default, three wire mode) and the clock is reasonably slow.
int main(int argc, char **argv) {
int res = bcm2835_init();
printf("BCM2835 Init() = %d\n", res);
res = bcm2835_spi_begin();
printf("BCM2835 Begin() = %d\n", res);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);
char data[16];
sprintf(data,"%s","<--Some data-->");
int len = strlen(data);
printf("Sent: %s\n", data);
bcm2835_spi_writenb(data, len);
exit(0);
}
Same results with spidev_test program using ioctl, so does not seem related to the library/Pi's program.
On top, what is puzzling me is that when I disconnect the wire from PB1 (MISO), I immediately start receiving garbage from Pi. As if Pi's SPI immediately starts clocking when PB1/MISO goes afloat.
What am I missing here?
Regretfully, I have to say that this one goes into the RTFM category.
After some reserch I found that Pi GPIO works with +3.3V. The Attiny was set to use+ 5V. After rewiring the AVR to work with 3.3V as well, everything seems to be working.
The reason why it worked in two wire mode is the absence of AVR's pull-up resistors (external required), which allowed Pi to use its own and drive the AVR pins in the range acceptable to both Pi and AVR. Enabling pull-ups on AVR would drive Pi's GPIO over the limit. Apparently no damage done, only unpredictable and hard to explain behavior.

arduino + serialport communication + ruby

I'm trying to turn on an LED connected to an Arduino from a ruby file, as well as sending a string from that Arduino to my ruby file / terminal. (I'm doing these two things separately, to avoid potential problems).
I'm using a USB port to connect Arduino - Computer, and the serialport gem. I'm working in Linux.
To receive the string on my computer:
I have followed several tutorials that all recommend to run this ruby file:
require 'serialport'
port_str = '/dev/ttyACM0'
baud_rate = 9600
data_bits = 8
stop_bits = 1
parity = SerialPort::NONE
sp = SerialPort.new(port_str, baud_rate, data_bits, stop_bits, parity)
while(true) do
message = sp.gets.chomp
puts message
end
And uploaded this to the Arduino:
uint8_t c;
int i;
void setup() {
Serial.begin(9600); // set baud rate
pinMode(13, OUTPUT); // set pin 13 to be output for LED
digitalWrite(13, LOW); // start with LED off
}
void loop() {
while (Serial.available() > 0) { // check if serial port has data
// writes to computer
Serial.println("Hello world");
}
}
I got this error message: undefined method `chomp' for nil:NilClass (NoMethodError). When getting rid of .chomp, at some point I could get some parts of "Hello world" being printed on my terminal, such as "Hell", and then far later "o w", etc.
Now I don't even get anything anymore.
To turn the led on:
In the ruby file, I replaced the message part by
sp.write('a')
And in the arduino file,
void loop() {
while (Serial.available() > 0) { // check if serial port has data
c = Serial.read(); // read the byte
if (c == 'a'){
digitalWrite(13, HIGH); // turn on LED
delay(500); // wait 500 milliseconds
digitalWrite(13, LOW); // turn off LED
delay(500); // wait 500 milliseconds
}
}
}
The led turns on if I remove the condition (c == 'a'), but obviously I need it if I want the arduino to perform different actions.
I'm new to Serial communication, so I'm not quite sure where the error comes from, since I feel somehow some data seems to be transmitted.

Resources