Related
I'm trying to call a C function from Fortran, using the iso_c_binding interoperability. However, I am getting a SegFault error when trying to use print and write statements. Without the print and write statements the code works fine, but I need these statements to create an output file with the simulation data. Does anyone know how to solve this problem?
Note: I am using Ubuntu 20.04, GFortran, and GCC to compile the respective source codes.
gcc -c subroutine_in_c.c
gfortran -o exec main.f90 subroutine_in_c.o -lwiringPi
main.f90:
PROGRAM main
USE, INTRINSIC:: iso_c_binding, ONLY: C_FLOAT
IMPLICIT NONE
REAL(KIND = 4) :: leitura_sensor = 0.0
INTERFACE
SUBROUTINE ler_sensores(s1) BIND(C)
USE, INTRINSIC :: iso_c_binding, ONLY: C_FLOAT
IMPLICIT NONE
REAL(KIND=C_FLOAT) :: s1
END SUBROUTINE ler_sensores
END INTERFACE
!print*, 'Call subroutine in C language'
call ler_sensores(leitura_sensor)
!print*, 'Return to main.f90'
OPEN(UNIT=1, FILE='output.txt', STATUS='unknown')
WRITE(1,*) leitura_sensor
CLOSE(UNIT=1)
END PROGRAM main
subroutine_in_c.c:
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPiSPI.h>
#include <wiringPiI2C.h>
#define LCDADDR 0x27 //IIC LCD address
#define BLEN 1 //1--open backlight,0--close backlight
#define CHAN_CONFIG_SINGLE 8 //setup channel 0 as Single-ended input
#define SPICHANNEL 0 //MCP3008 connect to SPI0
#define ANALOGCHANNEL 0 //Potentiometer connect MCP3008 analog channel 0
#define ANALOGCHANNEL2 1
static int spifd;
static int i2cfd;
void
spiSetup (int spiChannel)
{
if ((spifd = wiringPiSPISetup (spiChannel, 10000)) < 0)
{
fprintf (stderr, "Can't open the SPI bus: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}
}
int
myAnalogRead(int spiChannel,int channelConfig,int analogChannel)
{
if (analogChannel<0 || analogChannel>7)
return -1;
unsigned char buffer[3] = {1}; // start bit
buffer[1] = (channelConfig+analogChannel) << 4;
wiringPiSPIDataRW(spiChannel, buffer, 3);
return ( (buffer[1] & 3 ) << 8 ) + buffer[2]; // get last 10 bits
}
//write a word to lcd
void
write_word(int data)
{
int temp = data;
if ( BLEN == 1 )
temp |= 0x08;
else
temp &= 0xF7;
wiringPiI2CWrite(i2cfd, temp);
}
//send command to lcd
void
send_command(int comm)
{
int buf;
// Send bit7-4 firstly
buf = comm & 0xF0;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (comm & 0x0F) << 4;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//send data to lcd
void
send_data(int data)
{
int buf;
// Send bit7-4 firstly
buf = data & 0xF0;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (data & 0x0F) << 4;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//initialize the lcd
void
init()
{
send_command(0x33); // Must initialize to 8-line mode at first
delay(5);
send_command(0x32); // Then initialize to 4-line mode
delay(5);
send_command(0x28); // 2 Lines & 5*7 dots
delay(5);
send_command(0x0C); // Enable display without cursor
delay(5);
send_command(0x01); // Clear Screen
wiringPiI2CWrite(i2cfd, 0x08);
}
//clear screen
void
clear()
{
send_command(0x01); //clear Screen
}
//Print the message on the lcd
void
write(int x, int y, char data[])
{
int addr, i;
int tmp;
if (x < 0) x = 0;
if (x > 15) x = 15;
if (y < 0) y = 0;
if (y > 1) y = 1;
// Move cursor
addr = 0x80 + 0x40 * y + x;
send_command(addr);
tmp = strlen(data);
for (i = 0; i < tmp; i++) {
send_data(data[i]);
}
}
void
ler_sensores(float *s1)
{
int adc;
int adc2;
int i;
float voltage;
float voltage2;
char buf[5];
if (wiringPiSetup() < 0)
{
fprintf(stderr,"Can't init wiringPi: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
spiSetup(SPICHANNEL);//init spi
i2cfd = wiringPiI2CSetup(LCDADDR); //init i2c
init(); //init LCD
clear(); //clear screen
for (i = 0; i <25; i++) {
adc = myAnalogRead(SPICHANNEL,CHAN_CONFIG_SINGLE,ANALOGCHANNEL);
adc2 = myAnalogRead(SPICHANNEL, CHAN_CONFIG_SINGLE, ANALOGCHANNEL2);
voltage = adc/1024.*20.0;
write(0,0,"Ch Linear:");
sprintf(buf,"%2.2f",voltage);//float change to string
write(10,0,buf);//print voltage on lcd
write(15,0,"V");//print unit
write(0,1,"Ch Logarit:");
voltage2 = adc2/1024.*20.0;
sprintf(buf,"%2.2f",voltage2);
write(11,1, buf);
write(16,1,"V");
delay(1000);
}
*s1 = voltage;
}
Thank you in advance to everyone who helps.
This question probably deserves an answer even if the reason for the problem is the obscure one, identified by Craig Estay.
Gfortran's runtime library, called when using the print and write statements, contains calls to write() and having another C function called write will cause the gfortran runtime to call a wrong function.
It can easily be tested in a simple program like this:
testwrite.c:
#include "stdio.h"
void write(){
puts("my C write");
}
testwrite.f90:
print *,"test print"
write(*,*) "test write"
end
When using gfortran testwrite.c testwrite.f90, the output is:
my C write
my C write
my C write
my C write
The same output appears when using icc testwrite.c -c -o c.o and ifort c.o testwrite.f90.
I am a newbie with DACs, but basically, I have a FPGA (DE1-SOC) running Linux. Hooked up to it is a LTC2607 DAC. Everything is operating smoothly as far as Linux recognizing the DAC over I2C and everything.
My question is regarding how to generate a sinusoidal waveform using the cordic algorithm. I have an algorithm that outputs an array of 16 hex values.
{0x00003243, 0x00001DAC, 0x00000FAD, 0x000007F5, etc...}
The code that runs the I2c/DAC accepts a 16-bit "DAC Code", which then is converted to an analog output:
uint16_t LTC2607_code(float dac_voltage, float LTC2607_lsb, float LTC2607_offset)
{
uint16_t dac_code;
float float_code;
float_code = (dac_voltage - LTC2607_offset) / LTC2607_lsb; // Calculate the DAC code
float_code = (float_code > (floor(float_code) + 0.5)) ? ceil(float_code) : floor(float_code); // Round
if (float_code >= 65535.0) // Limits the DAC code to 16 bits
float_code = 65535.0;
dac_code = (uint16_t) (float_code); // Convert to unsigned integer
return (dac_code);
}
I know for direct digital synthesis you have to "interpolate" the points (voltage levels) along the sinusoid. My thinking is that I would send those value across the I2C, one-by-one, and however fast those 16 hex values are passed across the I2C (set by the Master (FPGA) clock # ~10MHz) is what frequency the sin wave will be?
The code for writing to the DAC is as follows:
int8_t LTC2607_write(uint8_t i2c_address, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
{
int fd;
int ret;
char *device;
uint8_t command_byte;
uint8_t buffer[3];
command_byte = dac_command | dac_address; // Build the DAC command byte
// Open the I2C device
device = LTC2607_get_device_name();
fd = open(device, O_RDWR);
if (fd < 0)
{
return (1);
}
// Select the desired address
ret = ioctl(fd, I2C_SLAVE, i2c_address);
if (ret < 0)
{
close(fd);
return (1);
}
// Build the I2C command
buffer[0] = command_byte;
buffer[1] = (dac_code >> 8) & 0xFF;
buffer[2] = dac_code & 0xFF;
// Write the command to the I2C bus
ret = write(fd, buffer, 3);
if (ret < 3)
{
close(fd);
return (1);
}
// Close the device
close(fd);
return (0);
}
How would I convert that string of 16 hex values into a sinusoid using the above LTC2607_write function?
--------------- EDIT: Additional Note -----------------------------------------
We just tried only migrating to Vivado 2016.1. With that version the SD card is working with the new functions, even if it destroys the audio codec somehow. Which is pretty interesting because we looked up every patch note from 2015.2 to 2016.4 and the only thing mentioned is that they added an additional data type for sd card I/O whoch is taken out again in the next version.
----------------END EDIT--------------------------------------------------------
We just migrated our robot project from vivado 2015.2 to 2016.4, after the upgrade the sd image is flashed when the fpga (zynq 7020) ist started but the processor code will not be executed. After some debugging we found out, that we have to create a new SDK project with new FSBL and BSP and include the source files with an new empty application. After this the program got stuck in a loop so we had to debug further. We then found out we had to replace our actual SD card functions ( those recommended in TRM UG585 ) with our old ones.
New SD functions:
void readBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS; // Choose baseaddress based on the desired SD-slot
// START
TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512; // (1) Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector; // (3) Set Argument Reg -> Readaddress
TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_READ; // (4/5) Set Transfer Mode / Command Reg -> CMD17, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Read, Disable Auto CMD12, Disable Block Count, Disable DMA
while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress)); // (6) Wait for Command Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK; // (7) Clear Command Complete Status
// (8) Get Response Data -> ignored, maybe checked for errors and retry
// (9) Write or Read -> Read
while(!SD_BUFFER_READ_RDY_INTERRUPT(baseaddress)); // (10-R) Wait for Buffer Read Ready Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_READ_RDY_MASK; // (11-R) Clear Buffer Read Ready Status
for(unsigned char i = 0; i< 128; i++) // (12-R) Get Block Data
buf[i] = TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET);
// (13-R) More Blocks? -> No
// (14) Single/Multi/Infinite Block Transfer? -> Single
while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress)); // (15) Wait for Transfer Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK; // (16) Clear Transfer Complete Status
// END
}
void writeBlock(unsigned char sd_id, unsigned int sector, unsigned int* buf){
unsigned int baseaddress = sd_id == 0 ? SD0_BASEADDRESS : SD1_BASEADDRESS; // Choose baseaddress based on the desired SD-slot
// START
TO_REG(baseaddress + SD_BLOCK_SIZE_REG_OFFSET) = SD_BLOCKCOUNT1_BLOCKSIZE512; // (1) Set Block Size Reg -> 512 Bytes, (2) Set Block Count Reg -> 1 Block
TO_REG(baseaddress + SD_ARGUMENT_REG_OFFSET) = sector; // (3) Set Argument Reg -> Readaddress
TO_REG(baseaddress + SD_TRANSFER_MODE_COMMAND_REG_OFFSET) = SD_SINGLEBLOCK_WRITE; // (4/5) Set Transfer Mode / Command Reg -> CMD24, Normal, Data Present, Enable Index-Check, Enable CRC-Check, Response length 48, Single Block, Write, Disable Auto CMD12, Disable Block Count, Disable DMA
while(!SD_CMD_COMPLETE_INTERRUPT(baseaddress)); // (6) Wait for Command Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_CMD_COMPLETE_MASK; // (7) Clear Command Complete
Status
// (8) Get Response Data -> ignored, maybe checked for errors and retry
// (9) Write or Read -> Write
while(!SD_BUFFER_WRITE_RDY_INTERRUPT(baseaddress)); // (10-W) Wait for Buffer Write Ready Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_BUFFER_WRITE_RDY_MASK; // (11-W) Clear Buffer Write Ready Status
for(unsigned char i = 0; i< 128; i++) // (12-W) Set Block Data
TO_REG(baseaddress + SD_BUFFER_DATA_PORT_REG_OFFSET) = buf[i];
// (13-W) More Blocks? -> No
// (14) Single/Multi/Infinite Block Transfer? -> Single
while(!SD_TRANSFER_COMPLETE_INTERRUPT(baseaddress)); // (15) Wait for Transfer Complete Interrupt
TO_REG(baseaddress + SD_INTERRUPT_STATUS_REG_OFFSET) = SD_INTERRUPT_STATUS_TRANSFER_COMPLETE_MASK; // (16) Clear Transfer Complete Status
// END
}
Old SD functiony:
DRESULT readBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){
unsigned int count = 1;
if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid
s32 Status;
DWORD LocSector = sector;
/* Convert LBA to byte address if needed */
if ((SdInstance[sd_id].HCS) == 0U) {
LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
}
Status = XSdPs_ReadPolled(&SdInstance[sd_id], (u32)LocSector, count,(unsigned char *) buff);
if (Status != XST_SUCCESS) {
return RES_ERROR;
}
return RES_OK;
}
DRESULT writeBlock(unsigned char sd_id, unsigned long sector, unsigned char* buff){
unsigned int count = 1;
if(sd_id > 1) return RES_ERROR; //only id = 0 or id = 1 is valid
s32 Status;
DWORD LocSector = sector;
/* Convert LBA to byte address if needed */
if ((SdInstance[sd_id].HCS) == 0U) {
LocSector *= (DWORD)XSDPS_BLK_SIZE_512_MASK;
}
Status = XSdPs_WritePolled(&SdInstance[sd_id], (u32)LocSector, count,buff);
if (Status != XST_SUCCESS) {
return RES_ERROR;
}
return RES_OK;
}
This fixed the problem with the processor code in general but we are still not able to initialize or do IO operations on the SD card. Additionally we found out that when initializing the SD the function getBusWidth (bsp) failes when it tries to call XSdPs_CmdTransfer() -> XSdPs_ReadReg(). Which also seems to be the case when we try to do IO ops on the SD card with our old functions.
SD init function:
unsigned char initSD(unsigned char sd_id){
if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid
DSTATUS s = 0;
s32 Status;
u8 SCR[8] = {0U};
u8 ReadBuff[64] = {0U};
XSdPs_Config *SdConfig = NULL;
/*
* Initialize the host controller
*/
SdConfig = &XSdPs_ConfigTable[sd_id];
Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_SdCardInitialize(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Change_ClkFreq(&SdInstance[sd_id], SD_CLK_25_MHZ);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Select_Card(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Get_BusWidth(&SdInstance[sd_id], SCR);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_Get_BusSpeed(&SdInstance[sd_id], ReadBuff);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
if((ReadBuff[13] & HIGH_SPEED_SUPPORT) != 0U){
Status = XSdPs_Change_BusSpeed(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
}
Status = XSdPs_Pullup(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
if ((SCR[1] & WIDTH_4_BIT_SUPPORT) != 0U) {
Status = XSdPs_Change_BusWidth(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
}
Status = XSdPs_SetBlkSize(&SdInstance[sd_id], (u16)XSDPS_BLK_SIZE_512_MASK);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
After this quite short description of our problem ;), now to my question. Has anyone of you encountered a similar problem and knows a workaround or can point us in a direction where we may find a solution?
Thanks in advance :).
Delet0r
So it worked before, which means your SD configuration seems to be right.
Have you tried the build in XSdPs_CardInitialize(...) function, instead of your customized initSD(...) function? The XSdPs_CardInitialize(...) is inside the xsdps.c of your sdps driver. This function is doing a lot more checks and also a few things in different order, as you are in your initSD(...).
So try this one:
unsigned char initSD(unsigned char sd_id){
if(sd_id > 1) return 0xFF; //only id = 0 or id = 1 is valid
DSTATUS s = 0;
s32 Status;
XSdPs_Config *SdConfig = NULL;
/*
* Initialize the host controller
*/
SdConfig = &XSdPs_ConfigTable[sd_id];
Status = XSdPs_CfgInitialize(&SdInstance[sd_id], SdConfig, SdConfig->BaseAddress);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
Status = XSdPs_CardInitialize(&SdInstance[sd_id]);
if (Status != XST_SUCCESS) {
s |= STA_NOINIT;
return s;
}
return Status;
}
We also tried it with Vivado 2016.3 which works for the SD cards even if we dont know why. We have not checked yet if everything else works, but it seems like a workaround for now.
Hopefully it gets fixed in 2017.1
I'm delving into OpenCL by making a Matrix dot product implementation. I'm having a problem with getting my kernels to return the same values as my host.
I have made an encapsulation function that allocates device memory, sets parameters to a kernel, runs the kernel and returns the result back to the host.
/* This function runs the matrix dot product on whatever OpenCL device
* you specify
*/
cl_int OpenCL_MatrixMul(cl_device_id * device, cl_context * context,
cl_command_queue * commandQueue, cl_kernel * matrixMulKernel, float * A_h,
float * B_h, float * C_h, const cl_uint HeightA, const cl_uint WidthB,
const cl_uint WidthAHeightB)
{
printf("Inside matrix mul, WidthA: %zu, WidthB: %zu, WidthAHeightB: %zu\n",
HeightA, WidthB, WidthAHeightB);
//this error variable will record any errors found and will be returned
//by this function
cl_int error = CL_SUCCESS;
cl_int clEnqueueReadBuffer_error;
//declare a place for the memory on the device, A is the A matrix,
//B is the B matrix, C is the C result matrix
cl_mem A_d, B_d, C_d;
//this is a temporary value for holding the maximum work group size
size_t maximum_local_ws;
//variable for holding the number of work items per group
size_t local_ws[2];
//variable for holding the number of work items
size_t global_ws[2];
//calcuate work group and local size
//get the maximum work group size for the kernel, i.e. set local_ws
clGetKernelWorkGroupInfo((* matrixMulKernel), (* device),
CL_KERNEL_WORK_GROUP_SIZE, sizeof(maximum_local_ws),
&maximum_local_ws, NULL);
//find the largest integer, power of 2, square root, for maximum_local_ws
//that is less than or equal to 16
for(size_t i = 1; (i * i) <= maximum_local_ws && i <= maxBlockSize; i *= 2)
{
local_ws[0] = i;
local_ws[1] = i;
}
//calculate global work size
global_ws[0] = WidthB;
global_ws[1] = HeightA;
printf("Work group size calculated.\n");
//Allocate global memory on the device
//put A on the device
A_d = clCreateBuffer ((* context), CL_MEM_COPY_HOST_PTR,
(WidthAHeightB * HeightA * sizeof(float)), A_h, &error);
//put B on the device
B_d = clCreateBuffer ((* context), CL_MEM_COPY_HOST_PTR,
(WidthB * WidthAHeightB * sizeof(float)), B_h, &error);
//create a space for C on the device
C_d = clCreateBuffer ((* context), CL_MEM_READ_WRITE,
(HeightA * WidthB * sizeof(float)), NULL, &error);
printf("Global memory allocated.\n");
if(error == CL_SUCCESS)
{
//set the prarameters of the kernels
//Put in A
error = clSetKernelArg((* matrixMulKernel), 0, sizeof(cl_mem), &A_d);
//Put in B
error |= clSetKernelArg((* matrixMulKernel), 1, sizeof(cl_mem), &B_d);
//Put in C
error |= clSetKernelArg((* matrixMulKernel), 2, sizeof(cl_mem), &C_d);
//Put in HeightA
error |= clSetKernelArg((* matrixMulKernel), 3, sizeof(cl_uint),
&HeightA);
//Put in WidthB
error |= clSetKernelArg((* matrixMulKernel), 4, sizeof(cl_uint),
&WidthB);
//Put in WidthAHeightB
error |= clSetKernelArg((* matrixMulKernel), 5, sizeof(cl_uint),
&WidthAHeightB);
printf("Parameters added to the kernel.\n");
if(error == CL_SUCCESS)
{
//execute the kernel
printf("Running Kernel, Local work size: %zu x %zu global worksize:
%zu x %zu, HeightA: %zu, WidthB: %zu, WidthAHeightB: %zu\n",
local_ws[0], local_ws[1], global_ws[0], global_ws[1],
HeightA, WidthB, WidthAHeightB);
error = clEnqueueNDRangeKernel((* commandQueue),
(* matrixMulKernel), 1, NULL, global_ws, local_ws, 0, NULL,
NULL);
printf("Kernel Ran.\n");
if(error == CL_SUCCESS)
{
printf("Kernel Launched Successfully\n");
}
else
{
printf("Kernel Not Launched\n");
}
}
}
else
{
printf("Parameters not added to the kernel.\n");
}
printf("Reading results back from device\n");
//read the result back to the host system, (copy C_h to C_d)
clEnqueueReadBuffer_error = clEnqueueReadBuffer((* commandQueue), C_d,
CL_TRUE, 0, HeightA * WidthB * sizeof(float), C_h, 0, NULL, NULL);
//make sure we don't write over previous errors, if
//clEnqueueReadBuffer_error has an error
if(error == CL_SUCCESS)
{
error = clEnqueueReadBuffer_error;
}
printf("Freeing device memory\n");
//Free global memory on the device
clReleaseMemObject(A_d);
clReleaseMemObject(B_d);
clReleaseMemObject(C_d);
return error;
}
This code, when run, it outputs something strange:
Inside matrix mul, WidthA: 16, WidthB: 16, WidthAHeightB: 16
Work group size calculated.
Global memory allocated.
Parameters added to the kernel.
Running Kernel, Local work size: 1 x 1 global worksize: 16 x 16, HeightA: 16, WidthB: 140733193388048, WidthAHeightB: 16
Kernel Ran.
Kernel Launched Successfully
Reading results back from device
Freeing device memory
For some reason, widthB changed its value from 16 to 140733193388048. The strange thing is, widthB is different, yet WidthA and WidthAHeightB, despite being used the same way, remain the same. Furthermore, the value 140733193388048 remains unusually deterministic throughout all the calls I give to it.
Consequently, the first row, of the matrix, that my device returns, is the same as the host, but the subsequent values are not.
I'm programming on Mac OS X using Apple's OpenCL implementation in Snow Leopard.
What is going on here, and how do you keep something like this from happening?
One of the reasons why my kernel wasn't returning the right answer was because I wasn't giving clEnqueueNDRangeKernel the right number of dimensions for the work group. I'm still getting the weird outputs for WidthB, which isn't comforting knowing my print outs won't be accurate if I want to try to debug my programs.
How to change the transmission of bytes via the port?
Was: Interrupt.
Need: According to the poll.
plug-in -> http://pastie.org/3994352
Client:
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include "comm.h" // Connect module
void main(void)
{
char cmd[128];
/* Set the COM port */
printf("Adjustable com-port ...\n");
OpenSerial(COM_1, SER_BAUD_9600, SER_STOP_2 | SER_BITS_8 | SER_PARITY_EVEN);
printf("Submitting a request for a connection ...\n");
WriteSer(0xFF);
while (1)
{
if (kbhit())
{
int c = getche();
if (c == 13) putch(10);
WriteSer(c);
}
if (DataReadyCount())
{
int c = ReadQueue();
if (c == 0xFF) break;
putch(c);
}
}
printf("Ending a connection ...\n");
CloseSerial();
}
I found a sample on the web which may be of value, at least in showcasing the polling vs. interrupt driven approaches. Note that the interrupt method needs calls to setvect, outportb, saving the old interrupt and restoring it, etc.
Don't ask about TSRs next. :)
// http://ragestorm.net
// serial communications example
// interrupt driven/polled method
#include <dos.h>
#include <conio.h>
#include <stdio.h>
// serial port base addresses:
#define COM1 (0x3f8)
#define COM2 (0x2f8)
// stack size for interrupt
#define STACK_SIZE 1024
// serial ports registers:
// receive buffer
#define RBR (0x0)
// transmitter hold
#define THR (0x0)
// interrupt enable
#define IER (0x1)
// interrupt identification
#define IIR (0x2)
// fifo control
#define FCR (0x2)
// line control
#define LCR (0x3)
// modem control
#define MCR (0x4)
// line status
#define LSR (0x5)
// modem status
#define MSR (0x6)
// scratch-pad
#define SPR (0x7)
// divisor lsb byte
#define DIVLSB (0x0)
// divisor msb byte
#define DIVMSB (0x1)
// possible irqs for com ports
int com_irqs[4] = {4, 3, 4, 3};
// the com port addr being used
int used_com_addr = 0;
// the irq being used if interrupt driven
int used_com_irq = 0;
// interrupt driven or polling method?
int intr_used = 0;
// built in stack for interrupt usage
unsigned char recv_stack[STACK_SIZE];
unsigned char* next_char = recv_stack;
// old handler address
void interrupt (*old_handler)(...) = NULL;
void interrupt new_handler(...);
// get com address from bios
unsigned short get_com_addr(int com_no)
{
if ((com_no <= 0) || (com_no >= 5)) return -1;
// bios seg addr
unsigned char* biosaddr = (unsigned char *)0x400;
// set irq according to com number
used_com_irq = com_irqs[com_no - 1];
// retreive addresses bios
return *(unsigned short*)&biosaddr[(com_no - 1) << 1];
}
// detect the uart type of the used com prot addr
// this is mainly to know if fifo is available.
// 0: no uart found, 1: 8250, 2: 16450 or 8250(with spr), 3: 16550, 4: 16550A
int detect_uart_type()
{
char old_data = 0;
// check UART presentation by checking loopback mode
old_data = inportb(used_com_addr + MCR);
outportb(used_com_addr + MCR, 0x10);
if ((inportb(used_com_addr + MSR) & 0xf0)) return 0;
outportb(used_com_addr + MCR, 0x1f);
if ((inportb(used_com_addr + MSR) & 0xf0) != 0xf0) return 0;
outportb(used_com_addr + MCR, old_data);
// write values to scratch pad and readback
old_data = inportb(used_com_addr + SPR);
outportb(used_com_addr + SPR, 0x55);
if (inportb(used_com_addr + SPR) != 0x55) return 1;
outportb(used_com_addr + SPR, 0xAA);
if (inportb(used_com_addr + SPR) != 0xAA) return 1;
outportb(used_com_addr + SPR, old_data);
// enable fifo and determine version by part identification
outportb(used_com_addr + FCR, 1);
old_data = inportb(used_com_addr + FCR);
outportb(used_com_addr + FCR, 0);
if ((~old_data & 0x80)) return 2; // 16450
if ((~old_data & 0x40)) return 3; // 16550
return 4; // 16550a +
}
// inits the serial com port with a specific baud rate,
// using interrupt or polling method.
void init_com_port(int com_no, long baudrate, int intr = 0)
{
// calculate divisor relative to the baudrate
short divisor = (long)115200 / baudrate;
used_com_addr = get_com_addr(com_no);
if (used_com_addr == 0) {
printf("no valid com port!\n");
return ;
}
printf("serial com port addr 0x%x", used_com_addr);
if (intr)
printf(" [irq %d, ", used_com_irq);
else printf("[");
int uart_type = detect_uart_type();
switch(uart_type) {
//case 0: break; // port must be found already by bios.
case 1: printf("8250"); break;
case 2: printf("16450"); break;
case 3: printf("16550"); break;
case 4: printf("16550a"); break;
}
printf("] is initialized!\n");
intr_used = intr;
disable();
// turn off interrupts
outportb(used_com_addr + 1, 0);
// set dlab bit, so we can update the divisor
outportb(used_com_addr + LCR, 0x80);
// set divisor lsb
outportb(used_com_addr + DIVLSB, divisor & 0xff);
// set msb
outportb(used_com_addr + DIVMSB, (divisor >> 8) & 0xff);
// frame: 8 data bits, no parity and 1 stop bit
outportb(used_com_addr + LCR, 0x3);
// set RTS | DTR | OUT2(if intr) to inform remote system that we are ready
outportb(used_com_addr + MCR, 0x3 | ((intr == 1) << 3));
// support interrupt?
if (intr) {
// save old serial port interrupt handler address
old_handler = getvect(8 + used_com_irq);
setvect(8 + used_com_irq, new_handler);
// enable serial port irq at pic
outportb(0x21, inportb(0x21) & ~(1 << used_com_irq));
// let the interrupt be triggered upon data arrival
outportb(used_com_addr + IER, 1);
} else {
// no interrupt should be triggered
outportb(used_com_addr + IER, 0);
}
// does the uart support fifo?
if (uart_type == 4) {
// set fifo buffer of 14 bytes, clear receive and transmit fifo's
outportb(used_com_addr + FCR, 0xc7);
}
// clear delta bits
inportb(used_com_addr + LSR);
// clear incoming byte
inportb(used_com_addr + RBR);
enable();
}
// the serial port interrupt handler
// called upon received data only
// saves data in a stack
void interrupt new_handler(...)
{
unsigned char status = 0;
disable();
// read iir and msr to acknowledge the uart
inportb(used_com_addr + IIR);
inportb(used_com_addr + MSR);
// as long as data is arriving, put it in the stack
do {
// read status register
status = inportb(used_com_addr + LSR) & 0x1;
if (status & 1) {
// read data from com port to the stack
*next_char++ = inportb(used_com_addr + RBR);
// overlap offset in case the stack is full
next_char = ((next_char - recv_stack) % STACK_SIZE) + recv_stack;
}
}while (status & 1);
enable();
// let the pic know we are done
outportb(0xa0, 0x20);
outportb(0x20, 0x20);
}
// send a byte to the initialized com port
void send_byte(unsigned char ch)
{
// make sure the connection is alive
if (inportb(used_com_addr + MSR) & 0x80 == 0) return;
// make sure the transmit hold register is empty
while (inportb(used_com_addr + LSR) & 0x20 == 0) ;
// send the character
outportb(used_com_addr + THR, ch);
}
// receive a byte from the initialized com port
unsigned char recv_byte(int* is_read)
{
int i;
*is_read = 0;
if (intr_used)
if (next_char > recv_stack)
{
*is_read = 1;
return *--next_char;
} else return 0;
// is data set ready high?
for (i = 5; i > 0; i--)
if (inportb(used_com_addr + MSR) & 0x20) break;
if (!i) return -1;
// is there anything to read?
for (i = 5; i > 0; i--)
if (inportb(used_com_addr + LSR) & 0x1) break;
if (!i) return -2;
*is_read = 1;
return inportb(used_com_addr + RBR);
}
// enter loop-mode for debugging and testing.
void enter_loop_mode()
{
outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) | 0x10);
}
// exit a loop mode, change to transimtter/receiver mode
void exit_loop_mode()
{
outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) & ~0x10);
}
// shut down serial port connection
void shutdown_com_port()
{
disable();
if (intr_used) {
// set the old handler
setvect(8 + used_com_irq, old_handler);
// disable used serial port interrupt at pic
outportb(0x21, inportb(0x21) | (1 << used_com_irq));
}
// disable serial port interrupt
outportb(used_com_addr + IER, 0);
// disable interrupt, RTS and DTR
outportb(used_com_addr + MCR, 0);
outportb(used_com_addr + FCR, 0);
enable();
}
int main()
{
clrscr();
init_com_port(1, 9600, 1);
for(;;) {
if (kbhit()) {
int c = getch();
if (c == 27) break;
printf("%c", c);
send_byte(c);
}
int b = 0;
unsigned char c = recv_byte(&b);
if (b) printf("%c", c);
}
shutdown_com_port();
return 1;
}