Async Usart IO_READ always null SAMD20J16 - c

Fairly new to the Atmel software framework, usually use MPLab/PIC devices but for my project I needed to build a UART router capable of connecting 6 UART devices together so I chose a SAMD20J16 chip. So far iv'e configured the drivers using ATMEL start with USART HAL_ASYNC drivers for all USART modules.
Iv'e gotten the device to write to all 6 USART modules and have gotten the read interrupt to trigger but I am unable to read from the usart buffer. For now ive stripped it down to the minimal code possible to try and find out why it's not working, it's probably a simple oversight on my part, but Iv'e been searching the internet for 2 days and all the documentation I can find using the HAL_ASYNC drivers in ASF4 is flaky at best.
#include <atmel_start.h>
int main(void)
{
int nRead=0;
uint8_t rxPData;
/* Initializes MCU, drivers and middleware */
atmel_start_init();
//DECLARE UART STRUCTURTES
struct io_descriptor *uartD1;
usart_async_get_io_descriptor(&USART_0, &uartD1);
usart_async_enable(&USART_0);
struct io_descriptor *uartP;
usart_async_get_io_descriptor(&USART_1, &uartP);
usart_async_enable(&USART_1);
struct io_descriptor *uartD3;
usart_async_get_io_descriptor(&USART_2, &uartD3);
usart_async_enable(&USART_2);
struct io_descriptor *uartD4;
usart_async_get_io_descriptor(&USART_3, &uartD4);
usart_async_enable(&USART_3);
struct io_descriptor *uartS;
usart_async_get_io_descriptor(&USART_4, &uartS);
usart_async_enable(&USART_4);
struct io_descriptor *uartD2;io_write(uartP, (uint8_t *) "UART P\r\n", 8);
usart_async_get_io_descriptor(&USART_5, &uartD2);
usart_async_enable(&USART_5);
void uartP_callback(const struct usart_async_descriptor *const io_descriptor){
if(usart_async_is_rx_not_empty(uartP)){
io_write(uartP, (uint8_t *) "TEST P\r\n", 8);
nRead=io_read(uartP,&rxPData,6);
io_write(uartP,&rxPData,nRead);
}
}
usart_async_register_callback(&USART_1, USART_ASYNC_RXC_CB, uartP_callback);
while (1) {
}
}
Right now the observed behavior is anytime I send a UART packet it triggers the interrupt, and passes the IF rx_buffer_is_not_empty and sends back "TEST P\r\n". I added this line of code after some testing just to see if the interrupt was triggering.
However, no matter what input size i send to it it never transmits back any data that was sent to it.
Right now i'm simply trying to verify that I can receive and transmit on all usart ports, the final code won't have transmits inside the receive interrupts.

Related

Mixed voltage reading from different AD7606 channels

Please help! I am using FSMC to connect a STM32F407 MCU with AD7606 to sample voltage value. MCU would send sampled values to PC using USB HS port after 1024 conversions. But when I inspect the values from PC, I found that readings from channel 0 occasionally contains data from other channels. For example, if connect channel 0 to 5v, connect channel 8 to 3.3v, connect other channels to ground. Then the printed value from channel 0 would contain 5v, 0v, 3.3v. The basic setup is as follows:
A 200KHZ PWM single is generated by TIM10 to act as CONVST signal for AD7606.
7606 will then issue a BUSY signal which I used as an external interrupt source.
In the Interrupt handler, An DMA request would be issued to read 8 16bit data
from FSMC address space to memory space. TIM10 PWM would be stopped if 1024
conversions has been done.
In the DMA XFER_CPLT call back, if 1024 conversions has been done, the converted
data would be sent out by USB HS port, and TIM10 PWM would be enabled again.
Some code blocks:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_7)
{
// DMA data from FSMC to memory
HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, 0x6C000000, (uint32_t)(adc_data + adc_data_idx) , 8);
adc_data_idx += 8;
if (adc_data_idx >= ADC_DATA_SIZE)
HAL_TIM_PWM_Stop(&htim10, TIM_CHANNEL_1);
}
}
void dma_done(DMA_HandleTypeDef *_hdma)
{
int i;
int ret;
// adc_data[adc_data_idx] would always contain data from
// channel 1, led1 wouldn't light if every thing is fine.
if (adc_data[adc_data_idx] < 0x7f00 )
HAL_GPIO_WritePin(led1_GPIO_Port, led1_Pin, GPIO_PIN_SET);
if (adc_data_idx >= ADC_DATA_SIZE)
{
if(hUsbDeviceHS.dev_state == USBD_STATE_CONFIGURED)
{
// if I don't call CDC_Transmit_HS, everything is fine.
ret = CDC_Transmit_HS((uint8_t *)(adc_data), ADC_DATA_SIZE * 2 );
if (ret != USBD_OK)
{
HAL_GPIO_WritePin(led1_GPIO_Port, led2_Pin, GPIO_PIN_SET);
}
}
adc_data_idx = 0;
HAL_TIM_PWM_Start(&htim10, TIM_CHANNEL_1);
}
}
It seems that a single USB transaction would take longer than 5us(one conversion time), so I stopped PWM signal to stop conversion...
If I only send the second half of the data buffer, there is no data mixture. It's very strange.
According to your description, I think the processing is correct, and the problem is at the CDC_Transmit_HS(); I have met the problem on the CDC_Transmit_FS(), which can't transmit more than 64 bytes data for original code, and need to modify some code, otherwise the some error occurs. Did you check the number of received data is correct?
Reference:
I can't receive more than 64 bytes on custom USB CDC class based STM32 device
I'm not sure your ADC_DATA_SIZE size; if it's larger than 64 bytes, maybe you can modify to smaller than 64 bytes and try again and check whether or not the data is correct. I am not sure if it is affected by this problem, but I think you can give it a try.
On the other hand, it may also be necessary to GND the ADC IN pins not used by AD7606 to avoid interference between channels.
Or you can try other communication (I2C, SPI, UART...etc) to send the data.
If there is no problem with other communication methods, there is a high chance that it is a problem with CDC_Transmit_HS(). If there are problems with other transmission methods, you may have to check whether there is a conflict between the ADC conversion time or the transmission time.

Why there is a word address in this I2C example code from FTDI?

I have been working on FTDI FT2232H chip to interface with I2C devices. I have started to learn AN_177 application note pdf. I have no EEPROM to expreience,no oscilloscope to see waveforms. My goal is to comprehend the code itself and taking notes for my future projects. Here is the code snippet that i dont completely understand:
FT_STATUS write_byte(uint8 slaveAddress, uint8 registerAddress, uint8 data)
{
uint32 bytesToTransfer = 0;
uint32 bytesTransfered;
bool writeComplete=0;
uint32 retry=0;
bytesToTransfer=0;
bytesTransfered=0;
buffer[bytesToTransfer++]=registerAddress; /* Byte addressed inside EEPROM */
buffer[bytesToTransfer++]=data;
status = I2C_DeviceWrite(ftHandle, slaveAddress, bytesToTransfer, buffer, &bytesTransfered, I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT);
/* poll to check completition */
while((writeComplete==0)&& (retry<I2C_WRITE_COMPLETION_RETRY))
{
bytesToTransfer=0;
bytesTransfered=0;
buffer[bytesToTransfer++]=registerAddress; /* Addressed inside EEPROM */
status = I2C_DeviceWrite(ftHandle, slaveAddress, bytesToTransfer,buffer, &bytesTransfered, I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_BREAK_ON_NACK);
if((FT_OK == status) && (bytesToTransfer == bytesTransfered))
{
writeComplete=1;
printf(" ... Write done\n");
}
retry++;
}
return status;
}
You can see and understand that the while loop is the polling part.
I checked the datasheet of 24LC024H I2C EEPROM and they mentioned about Acknowladge Polling (Page 10) is a feature of this kind of EEPROMs'. Acknowladge Polling basicly checks when the device is ready to send data. There is a flow diagram too... you could take a look.
Flowchart
Here comes the what i want to point out:
buffer[bytesToTransfer++]=registerAddress; /* Addressed inside EEPROM */
In the 24LC024H datasheet related to Acknowladge Polling they say polling part consist of START + Control Byte (or Slave address) + R/W bit, not include address inside EEPROM (Word address in I2C protocol) . So why FTDI guys included this line of code? Am I missing something?
Best regards...

Using UART to check data receiving from SPH0645 Mic I2S protocol

I'm trying to interface these SPH0645 Mics (I2S) to a STM32f767ZI board.
I have wired it correctly, now just trying to test the mic by passing the data through UART to my pc. Hoping someone can point me in the correct direction.
I have tried passing straight to the UART transmit. However I think I may need some datahandling - I am receiving from the UART, but sometimes just 0 or other times just gibberish which is not from the Mic as it still transmits even when i disconnect the mic.
I2S mic is receiving data in 24 bits in 32 bit frame, the last 8 bits are junk. The protocol is Big Endian, I am thinking that the HAL library handles this, however I am not completely sure.
uint16_t data;
while (1)
{
/* USER CODE END WHILE */
HAL_StatusTypeDef result= HAL_I2S_Receive(&hi2s1,&data,2,100);
HAL_UART_Transmit(&huart3,&data,2,100);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
What did I miss?
Check the return value of HAL_I2S_Receive(&hi2s1, &data, 1, 100)
Did you verify HAL_I2S_Receive expects uint32_t* as 2nd argument? I think it shall expect uint16_t*
Using HAL_UART_Transmit you want to transmit the data over UART. Shouldn't you pass data as an argument to HAL_UART_Transmit ?

AVR atmega128 Serial comminucation

I have a problem in connecting ATmega128 serial port to computer via USB-Serial converter. The USB-Serial converter is verified as I have connected computer to CDMA modem using it. However when I try to connect it with atmega128 I can't figure out the problem. I have connected it to serial LCD (CLCD) and it works fine.Even in simulation with virtual terminal there is no problem. I would like to know if I have missed anything related to serial port. I have already checked baud rate in hardware options and in virtual terminal.
Here is the code.
#include<avr/io.h>
#include<util/delay.h>
char str1[]="AT\r\n";
char str2[]="AT+CMGF=1\r\n";
char str3[]="AT+CMGS=\"01068685673\"\r\n";
char str4[]="hello\x1A\r\n";
int i;
void TX_CHAR(char ch)
{
while(!(UCSR1A&0x20));
UDR1=ch;
}
int main()
{
UBRR1H=0; UBRR1L=103; UCSR1B=0x08;
UCSR1C=0b00000110;
while(1)
{
i=0; while(str1[i])TX_CHAR(str1[i++]);
_delay_ms(200);
i=0; while(str2[i])TX_CHAR(str2[i++]);
_delay_ms(200);
i=0; while(str3[i])TX_CHAR(str3[i++]);
_delay_ms(200);
i=0; while(str4[i])TX_CHAR(str4[i++]);
_delay_ms(3000);
}
}
Things to check:
hardware - wiring
value of M103C fuse (= compatibility mode)
XTAL frequency and prescalers, as the formula for BAUD depends on it: BAUD = Fosc/16(UBRR+1)
USART double speed flag (UCSRA)
frame format
UDREn flag set
You also may get better insight into your code if you use predefined symbolic values, e.g.
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
see the examples in the data sheet (pg 176ff)
On the frame format I understand you are set to async, 8-bit (UCSR1B:2 = 0, UCSR1C:2,1 = 11), parity disabled, 1 stop bit
In void TX_CHAR(char ch) I understand you are checking the status of bit 7 (RXC1) by using mask 0x20H. On the other hand you dont have the RX enabled (RXEN1 meaning UCSR1B:4=0)
I wonder if you shouldn't better check bit 6 (TXC1). Again ... using the symbolic values would help to better understand the code.
Hope this helps ...

Raspberry Pi spidev.h SPI Communication

I try to establish a spi communication from RPi (Master) to an EtherCAT Device (Slave).
The transfer of data got a scheme.
I have to transfer 2 bytes which address registers and the following bytes transfer data till a chip select terminates the communication.
This is my created attempt. With cs_change, i can tell my spi communication to deselect Chip Select before the next transfer starts.
char transfer(UINT8 data, char last)
{
char last_transfer = last;
int ret;
uint8_t tx[] = { data };
uint8_t rx[ARRAY_SIZE(tx)] = { };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.cs_change = 0,
};
if (last_transfer)
tr.cs_change = 1;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
printf("can't send spi message");
return rx[tr.len-1];
}
First problem:
I think it is too late to deselect Chip Select first at new transfer.
So my first question: Is there another way to control my Chip Select signal, maybe another library i can use?!
Second problem:
I want to read from spi without writing on it, how can i realise that ( with a simple read(fd...) ?!)
I hope you guys can support me :)
Now this is spidev_test.c application you are referring to. The implementation seems to work as slave SPI device would be deselected after your last transfer. It stays selected until after the last transfer in a message.
Each SPI device is deselected when it's not in active use, allowing other drivers to talk to other devices as may be your SPI bus is shared among other slave SPI devices.
And moreover you are going for full-duplex.
Standard read() operation is obviously only half-duplex.
So whenever your SPI slave device wants to send data to the SPI controller(Master), then it must have some interrupt mechanism so that your driver/app can set the SPI controller to "SPI_IOC_RD_MODE" and can make "SPI_IOC_MESSAGE" providing only rx_buf OR you can go for only simple read() operation as the transfer would be half_duplex after setting the SPI controller to read mode. -Sumeet
You can use SPI_NO_CS mode and toggle the CS pins as GPIO using the wiringPi library... (from http://wiringpi.com/ )

Resources