Commit dfa91a3bc3fea741b18f1a2f3e1bb0d695444b33
1 parent
cc228d59b9
Exists in
master
libad9915 : add initial sources & include files
Showing 6 changed files with 541 additions and 0 deletions Inline Diff
include/ad9915.h
File was created | 1 | /* | ||
2 | dds initialisation et SPI | |||
3 | */ | |||
4 | ||||
5 | #include <stdint.h> | |||
6 | #include <unistd.h> | |||
7 | #include <stdio.h> | |||
8 | #include <stdlib.h> | |||
9 | #include <getopt.h> | |||
10 | #include <fcntl.h> | |||
11 | #include <sys/ioctl.h> | |||
12 | #include <linux/types.h> | |||
13 | #include <linux/spi/spidev.h> | |||
14 | /* memory management */ | |||
15 | #include <sys/mman.h> | |||
16 | #include "spi.h" | |||
17 | #include <string.h> | |||
18 | #include <math.h> | |||
19 | #include <time.h> | |||
20 | ||||
21 | ||||
22 | static const char CFRAddress[] = {0x00,0x01,0x02,0x03}; | |||
23 | ||||
24 | static const char CFR1Start[] ={0x00, 0x01, 0x00, 0x0a}; | |||
25 | //static const char CFR1Start[] ={0x00, 0x01, 0x01, 0x08}; //with osk enable | |||
26 | static const char CFR2Start[] ={0x00, 0x80, 0x09, 0x00}; //0x80 enable prof mode | |||
27 | static const char CFR3Start[] = {0x00, 0x00, 0x19, 0x1C}; | |||
28 | static const char CFR4Start[] = {0x00, 0x05, 0x21, 0x20}; | |||
29 | ||||
30 | static const char USR0Address = 0x1B; | |||
31 | static const char FTW0Address = 0x0b; //profile 0 ftw | |||
32 | static const char PA0Address = 0x0c; //profile 0 | |||
33 | ||||
34 | static const char DACCalEnable[] = {0x01, 0x05, 0x21, 0x20}; //Command to enable the DAC Cal, should be 0x01XXXXXX, where X is the last 6 digits of CFR4Start | |||
35 | ||||
36 | ||||
37 | void Send_Reset(int f_dds); | |||
38 | void Send_IO_Update (int f_dds); //Send the update to set the control registers | |||
39 | void write_register (int fd, unsigned char addr, unsigned char d3, unsigned char d2, unsigned char d1, unsigned char d0); | |||
40 | void Initialize_DDS (int fd, int f_dds); |
include/ddsFreq.h
File was created | 1 | #include <stdlib.h> | ||
2 | #include <stdio.h> | |||
3 | #include <unistd.h> | |||
4 | #include <math.h> | |||
5 | ||||
6 | struct frac | |||
7 | { | |||
8 | long double numerator; | |||
9 | long double denominator; | |||
10 | }; | |||
11 | ||||
12 | long double pgcd ( long double m , long double n); |
include/spi.h
File was created | 1 | #ifndef SPI_H | ||
2 | #define SPI_H | |||
3 | ||||
4 | int configureSpi(char *device); | |||
5 | uint16_t transfer(int fd, uint16_t valeur, int truc); | |||
6 | uint8_t spi_put(int fd, uint8_t valeur); | |||
7 | uint8_t spi_put_multiple(int fd, uint8_t *tx, uint16_t tx_size, | |||
8 | uint8_t *rx, uint16_t rx_size); | |||
9 | void setMode(int fd, uint8_t mode); | |||
10 | uint8_t tr2(int fd, uint8_t val); | |||
11 | uint8_t tr3(int fd, uint8_t *val, uint8_t *rx, uint8_t size); | |||
12 | int configureSpiFromFd (int fd); |
src/ad9915.c
File was created | 1 | /* | ||
2 | SPI : initialisation du dds et communication SPI | |||
3 | */ | |||
4 | #include"ad9915.h" | |||
5 | #include "spi.h" | |||
6 | #include "ddsFreq.h" | |||
7 | ||||
8 | #define debug | |||
9 | //fonction reset | |||
10 | void Send_Reset(int f_dds) | |||
11 | { | |||
12 | char reset='2'; | |||
13 | write(f_dds,&reset,sizeof(reset)); //reset | |||
14 | sleep(0.1); | |||
15 | } | |||
16 | ||||
17 | //fonction ioupdate | |||
18 | void Send_IO_Update(int f_dds) | |||
19 | { | |||
20 | char update='1'; | |||
21 | write(f_dds,&update,sizeof(update)); //reset | |||
22 | sleep(0.1); | |||
23 | } | |||
24 | ||||
25 | //fonction write register | |||
26 | void write_register (int fd, unsigned char addr, unsigned char d3, unsigned char d2, unsigned char d1, unsigned char d0) | |||
27 | { | |||
28 | unsigned char tx[5]={0}; | |||
29 | tx[0]=addr; | |||
30 | tx[1]=d3; | |||
31 | tx[2]=d2; | |||
32 | tx[3]=d1; | |||
33 | tx[4]=d0; | |||
34 | //spi_put_multiple envoie le vecteur dans cet ordre | |||
35 | //[tx0]-[tx1]-[tx2] -> adresse->bit poids Fort->bit poids faible | |||
36 | spi_put_multiple(fd,tx,5,NULL,0); | |||
37 | } | |||
38 | ||||
39 | //initialisation du dds | |||
40 | void Initialize_DDS (int fd, int f_dds) | |||
41 | { | |||
42 | Send_Reset(f_dds); | |||
43 | write_register(fd,CFRAddress[0],CFR1Start[0], CFR1Start[1], CFR1Start[2], CFR1Start[3]); | |||
44 | Send_IO_Update (f_dds); //Send the update to set the control registers | |||
45 | write_register(fd,CFRAddress[1], CFR2Start[0], CFR2Start[1], CFR2Start[2], CFR2Start[3]); | |||
46 | Send_IO_Update (f_dds); | |||
47 | write_register(fd,CFRAddress[2], CFR3Start[0], CFR3Start[1], CFR3Start[2], CFR3Start[3]); | |||
48 | Send_IO_Update (f_dds); | |||
49 | write_register(fd,CFRAddress[3], CFR4Start[0], CFR4Start[1], CFR4Start[2], CFR4Start[3]); | |||
50 | Send_IO_Update (f_dds); | |||
51 | write_register(fd,USR0Address, 0xA2, 0x00, 0x08, 0x00); | |||
52 | Send_IO_Update (f_dds); | |||
53 | } | |||
54 | ||||
55 | //calibration du dac | |||
56 | void Calibrate_DAC (int fd, int f_dds) | |||
57 | { | |||
58 | write_register(fd,CFRAddress[3], DACCalEnable[0], DACCalEnable[1], DACCalEnable[2], DACCalEnable[3]); | |||
59 | Send_IO_Update (f_dds); | |||
60 | write_register(fd,CFRAddress[3], CFR4Start[0], CFR4Start[1], CFR4Start[2], CFR4Start[3]); | |||
61 | Send_IO_Update (f_dds); | |||
62 | } | |||
63 | ||||
64 | void modulus_setup(int fd, int f_dds) | |||
65 | { | |||
66 | write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable | |||
67 | Send_IO_Update (f_dds); | |||
68 | write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp | |||
69 | Send_IO_Update (f_dds); | |||
70 | } | |||
71 | ||||
72 | void basic_setup(int fd, int f_dds,uint16_t ampWord, uint16_t phaseWord) | |||
73 | { | |||
74 | write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable | |||
75 | Send_IO_Update (f_dds); | |||
76 | write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp | |||
77 | Send_IO_Update (f_dds); | |||
78 | write_register(fd,0x04,0x19, 0x99, 0x99, 0x99); //ftw | |||
79 | Send_IO_Update (f_dds); | |||
80 | write_register(fd,0x05,0xC0, 0x00, 0x00, 0x00); //A | |||
81 | Send_IO_Update (f_dds); | |||
82 | write_register(fd,0x06,0x00, 0x00, 0x00, 0x05); //B | |||
83 | Send_IO_Update (f_dds); | |||
84 | //write_register(fd,0x0c, 0x0F, 0xFF, 0x00, 0x00); // amp (12b) ph(16) | |||
85 | write_register(fd,0x0c, (uint8_t)((ampWord>>8) & 0x0F), (uint8_t)(ampWord & 0xFF), (uint8_t)((phaseWord>>8) & 0xFF), (uint8_t)(phaseWord & 0xFF)); // amp (12b) ph(16) | |||
86 | Send_IO_Update (f_dds); | |||
87 | } | |||
88 | ||||
89 | void setFreqMM(int fd, int f_dds, unsigned int ftw, unsigned int A, unsigned int B) | |||
90 | { | |||
91 | //uint16_t phaseWord = 0x7400; | |||
92 | //uint16_t ampWord = (uint16_t)strtol(argv[4],NULL,0) & 0x0FFF ; //masque en 2 | |||
93 | //uint16_t ampWord = 0x00000FFF; | |||
94 | //uint32_t phaseAmpWord = phaseWord | ampWord<<16; | |||
95 | ||||
96 | //write_register(fd,0x00,0x00, 0x01, 0x01, 0x08); //OSK enable | |||
97 | //Send_IO_Update(f_dds); | |||
98 | //write_register(fd,0x01,0x00, 0x89, 0x09, 0x00); //enable program modulus and digital ramp | |||
99 | //Send_IO_Update(f_dds); | |||
100 | write_register(fd,0x04,ftw>>24&0xFF, ftw>>16&0xFF, ftw>>8&0xFF, ftw&0xFF); //ftw | |||
101 | Send_IO_Update(f_dds); | |||
102 | write_register(fd,0x05,A>>24&0xFF,A>>16&0xFF, A>>8&0xFF, A&0xFF); //A | |||
103 | Send_IO_Update(f_dds); | |||
104 | write_register(fd,0x06,B>>24&0xFF,B>>16&0xFF, B>>8&0xFF, B&0xFF); //B | |||
105 | Send_IO_Update(f_dds); | |||
106 | // write_register(fd,0x0c, phaseAmpWord>>24&0xFF, phaseAmpWord>>16&0xFF,phaseAmpWord>>8&0xFF,phaseAmpWord&0xFF); // amp (12b) ph(16) | |||
107 | //Send_IO_Update(f_dds); | |||
108 | } | |||
109 | ||||
110 | void setAmpPhaseWord(int fd, int f_dds,unsigned int phaseAmpWord) | |||
111 | { | |||
112 | write_register(fd,0x0c, phaseAmpWord>>24&0xFF, phaseAmpWord>>16&0xFF,phaseAmpWord>>8&0xFF,phaseAmpWord&0xFF); // amp (12b) ph(16) | |||
113 | Send_IO_Update(f_dds); | |||
114 | } | |||
115 | ||||
116 | ||||
117 | int openAndSetDdsFreq( char * device, char * gpio_update, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord) | |||
118 | { | |||
119 | #ifdef debug | |||
120 | printf("device=%s\tgpio_update=%s\tf_clk=%e\tf_out=%e\tampWord=%d\tphaseWord=%d\n\n",device,gpio_update,f_clk,f_out,ampWord,phaseWord); | |||
121 | #else | |||
122 | printf("device=%s\tgpio_update=%s\tf_clk=%e\tf_out=%e\tampWord=%d\tphaseWord=%d\n\n",device,gpio_update,f_clk,f_out,ampWord,phaseWord); | |||
123 | int fd=configureSpi(device); //ex #define FILENAME2 "/dev/spidev0.0" | |||
124 | printf("fd(funct)=%d\n",fd); | |||
125 | setMode(fd,SPI_MODE_0); | |||
126 | if (fd <= 0){ | |||
127 | printf("ERREUR : ouverture pรฉriphรฉrique SPI %s\n",device); | |||
128 | return EXIT_FAILURE; | |||
129 | } | |||
130 | int f_dds=open(gpio_update,O_RDWR); //ex #define UPDATE2 "/sys/dds/gpio24/updateOn" | |||
131 | printf("f_dds(funct)=%d\n",f_dds); | |||
132 | if (f_dds <= 0){ | |||
133 | printf("ERREUR : ouverture ");printf(gpio_update);printf("\n"); | |||
134 | printf("Chargez le module ddsIOupdateX\n"); | |||
135 | return EXIT_FAILURE; | |||
136 | } | |||
137 | setddsFreq(fd,f_dds,f_out,f_clk); | |||
138 | //debug | |||
139 | phaseWord = 0x0000; | |||
140 | ampWord=0x0FFF; | |||
141 | uint32_t phaseAmpWord = phaseWord | ampWord<<16; | |||
142 | setAmpPhaseWord(fd, f_dds, phaseAmpWord); | |||
143 | #endif | |||
144 | return EXIT_SUCCESS; | |||
145 | } | |||
146 | ||||
147 | int setDdsFreqFull ( int fd, int f_dds, double f_clk, double f_out, uint16_t ampWord, uint16_t phaseWord) | |||
148 | { |
src/ddsFreq.c
File was created | 1 | #include <stdlib.h> | ||
2 | #include <stdio.h> | |||
3 | #include <unistd.h> | |||
4 | #include <math.h> | |||
5 | #include "ddsFreq.h" | |||
6 | #include "ad9915.h" | |||
7 | ||||
8 | //#define debug | |||
9 | long double pgcd ( long double m , long double n) | |||
10 | { | |||
11 | if (fmod(m,n) ==0) | |||
12 | return n; | |||
13 | return pgcd(n,fmod(m,n)); | |||
14 | } | |||
15 | ||||
16 | int setddsFreq(int fd, int f_dds, long double f0, long double fs) | |||
17 | { | |||
18 | ||||
19 | #ifdef debug | |||
20 | printf("f0=%Le\tfs=%Le\n",f0,fs); | |||
21 | #endif | |||
22 | ||||
23 | if (fs<0 || f0<0) return EXIT_FAILURE; | |||
24 | ||||
25 | struct frac f1; | |||
26 | ||||
27 | f1.numerator = f0; | |||
28 | f1.denominator = fs; | |||
29 | ||||
30 | long double d1 = pgcd (f1.numerator , f1.denominator ); | |||
31 | //printf(" d1 = %24.16Lf\n",d1); | |||
32 | ||||
33 | long double M = f0 / d1 ; | |||
34 | long double N = fs / d1 ; | |||
35 | //printf(" M = f0 / d1 = %24.16Lf\n",M); | |||
36 | //printf(" N = fs / d1 = %24.16Lf\n",N); | |||
37 | ||||
38 | ||||
39 | long double ftw = M * scalbn(1.0,32); | |||
40 | ftw /= N; | |||
41 | //printf("ftw = %24.16Lf\n",ftw); | |||
42 | ||||
43 | ||||
44 | //printf("X=floor(ftw) = %24.16Lf\n",(long double)floor(ftw)); | |||
45 | ||||
46 | long double Y = M * scalbn(1.0,32); | |||
47 | Y -= N * floor(ftw); | |||
48 | //printf("Y=M*2**32-X*N = %24.16Lf\n",Y); | |||
49 | ||||
50 | long double d2 = pgcd (Y,N); | |||
51 | //printf(" d2 = %24.16Lf\n",d2); | |||
52 | ||||
53 | long double A = Y / d2; | |||
54 | long double B = N / d2; | |||
55 | //printf("A = Y/d2 = %24.16Lf\n",A); | |||
56 | //printf("B = N/d2 = %24.16Lf\n",B); | |||
57 | ||||
58 | //printf("f0 = (M/N) * fclk= %24.32Lf\n",fs*M/N); | |||
59 | //printf("f0 = (X+A/B)2**32= %24.32Lf\n",fs*(floor(ftw)+A/B)/scalbn(1.0,32)); | |||
60 | ||||
61 | #ifdef debug | |||
62 | printf("\n so finally the programmed registers are :\n" | |||
63 | "ftw= 0x%08x A= 0x%08x B= 0x%08x\n" | |||
64 | "",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); | |||
65 | printf("uint ftw = %d\n",(unsigned int)ftw); | |||
66 | ||||
67 | printf("\n 0x%08x 0x%08x 0x%08x \n\n",(unsigned int)ftw,(unsigned int)A,(unsigned int)B); | |||
68 | //setFreqMM(fd,f_dds,(unsigned int)ftw, (unsigned int)A, (unsigned int)B); | |||
69 | #endif | |||
70 | setFreqMM(fd,f_dds,(unsigned int)ftw, 2*(unsigned int)B, 2*(unsigned int)A); //??why *2?? | |||
71 | return EXIT_SUCCESS; | |||
72 | } | |||
73 | int ddsFreq(int fd, int f_dds) | |||
74 | { | |||
75 | //checkSize(); | |||
76 | long double f0,fs; | |||
77 | //printf("long = %lu\n",sizeof (long)); | |||
78 | //printf("float = %lu\n",sizeof (float)); | |||
79 | //printf("double = %lu\n",sizeof (double)); | |||
80 | //printf("long double = %lu\n",sizeof (long double)); | |||
81 | ||||
82 | printf("\nDesired output Frequency (MHz) : "); | |||
83 | scanf("%Lf",&f0); | |||
84 | printf("DDS frequency Clock (MHz) : "); | |||
85 | scanf("%Lf",&fs); | |||
86 | ||||
87 | //long double f0=atof(argv[1]); //desired output freq | |||
88 | //long double fs=atof(argv[2]); //dds_clk | |||
89 | //int toto = (int)strtol(argv[3],NULL,0); | |||
90 | //printf("toto=%d\t%x\n",toto,toto); | |||
91 | ||||
92 | if (fs<0 || f0<0) return EXIT_FAILURE; | |||
93 | ||||
94 | struct frac f1; | |||
95 | ||||
96 | f1.numerator = f0; | |||
97 | f1.denominator = fs; | |||
98 | ||||
99 | long double d1 = pgcd (f1.numerator , f1.denominator ); | |||
100 | printf(" d1 = %24.16Lf\n",d1); | |||
101 | ||||
102 | long double M = f0 / d1 ; | |||
103 | long double N = fs / d1 ; | |||
104 | printf(" M = f0 / d1 = %24.16Lf\n",M); |
src/spi.c
File was created | 1 | #include <stdint.h> | ||
2 | #include <unistd.h> | |||
3 | #include <stdio.h> | |||
4 | #include <stdlib.h> | |||
5 | #include <getopt.h> | |||
6 | #include <fcntl.h> | |||
7 | #include <sys/ioctl.h> | |||
8 | #include <linux/types.h> | |||
9 | #include <linux/spi/spidev.h> | |||
10 | /* memory management */ | |||
11 | #include <sys/mman.h> | |||
12 | #include "spi.h" | |||
13 | #include <string.h> | |||
14 | ||||
15 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | |||
16 | ||||
17 | #undef DEBUG | |||
18 | //#define DEBUG | |||
19 | static uint8_t bits = 8; | |||
20 | //static uint32_t speed = 15000000; // 9600; | |||
21 | //static uint32_t speed = 20000000; // 9600; | |||
22 | static uint32_t speed = 10000000; | |||
23 | //static uint32_t speed = 100000; // 9600; | |||
24 | //static uint16_t delay; | |||
25 | static void | |||
26 | pabort (const char *s) | |||
27 | { | |||
28 | perror (s); | |||
29 | abort (); | |||
30 | } | |||
31 | ||||
32 | uint8_t | |||
33 | spi_put_multiple (int fd, uint8_t * tx, uint16_t tx_size, | |||
34 | uint8_t * rx, uint16_t rx_size) | |||
35 | { | |||
36 | int ret; | |||
37 | int nb = 2; | |||
38 | if (rx_size == 0 || tx_size == 0) | |||
39 | nb = 1; | |||
40 | struct spi_ioc_transfer xfer[nb]; | |||
41 | nb = 0; | |||
42 | memset (xfer, 0, sizeof (xfer)); | |||
43 | if (tx_size > 0) | |||
44 | { | |||
45 | xfer[nb].tx_buf = (unsigned long) tx; | |||
46 | xfer[nb].len = tx_size; | |||
47 | nb++; | |||
48 | } | |||
49 | if (rx_size > 0) | |||
50 | { | |||
51 | xfer[nb].rx_buf = (unsigned long) rx; | |||
52 | xfer[nb].len = rx_size; | |||
53 | nb++; | |||
54 | } | |||
55 | ret = ioctl (fd, SPI_IOC_MESSAGE (nb), xfer); | |||
56 | return ret; | |||
57 | } | |||
58 | ||||
59 | uint8_t | |||
60 | tr3 (int fd, uint8_t * val, uint8_t * rx, uint8_t size) | |||
61 | { | |||
62 | int ret; | |||
63 | ||||
64 | struct spi_ioc_transfer xfer[2]; | |||
65 | memset (xfer, 0, sizeof (xfer)); | |||
66 | ||||
67 | xfer[0].tx_buf = (unsigned long) val; | |||
68 | xfer[0].len = size; | |||
69 | xfer[1].rx_buf = (unsigned long) rx; | |||
70 | xfer[1].len = size; | |||
71 | ||||
72 | ret = ioctl (fd, SPI_IOC_MESSAGE (2), xfer); | |||
73 | if (ret < 1) | |||
74 | { | |||
75 | pabort ("can't send spi message"); | |||
76 | } | |||
77 | return ret; | |||
78 | } | |||
79 | ||||
80 | void | |||
81 | setMode (int fd, uint8_t mode) | |||
82 | { | |||
83 | if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0) | |||
84 | pabort ("can't set mode"); | |||
85 | if (ioctl (fd, SPI_IOC_RD_MODE, &mode) < 0) | |||
86 | pabort ("can't get mode"); | |||
87 | } | |||
88 | ||||
89 | uint8_t | |||
90 | spi_put (int fd, uint8_t valeur) | |||
91 | { | |||
92 | int ret; | |||
93 | uint8_t rx_buf[1], tx_buf[1]; | |||
94 | tx_buf[0] = valeur; | |||
95 | struct spi_ioc_transfer xfer[2]; | |||
96 | memset (xfer, 0, sizeof (xfer)); | |||
97 | ||||
98 | xfer[0].tx_buf = (unsigned long) tx_buf; | |||
99 | xfer[0].rx_buf = (unsigned long) rx_buf; | |||
100 | xfer[0].len = 1; | |||
101 | ret = ioctl (fd, SPI_IOC_MESSAGE (1), xfer); | |||
102 | if (ret < 1) | |||
103 | { | |||
104 | pabort ("can't send spi message"); | |||
105 | } | |||
106 | return rx_buf[0]; | |||
107 | } | |||
108 | ||||
109 | int | |||
110 | configureSpi (char *device) | |||
111 | { | |||
112 | printf("device(configureSpi)=%s\n",device); | |||
113 | int fd = open (device, O_RDWR); | |||
114 | if (fd < 0) | |||
115 | pabort ("can't open device"); | |||
116 | ||||
117 | setMode (fd, 0); | |||
118 | /* bits per word */ | |||
119 | if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) | |||
120 | pabort ("can't set bits per word"); | |||
121 | if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) | |||
122 | pabort ("can't get bits per word"); | |||
123 | ||||
124 | /* max speed hz */ | |||
125 | if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) | |||
126 | pabort ("can't set max speed hz"); | |||
127 | ||||
128 | if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) | |||
129 | pabort ("can't get max speed hz"); | |||
130 | //#ifdef DEBUG | |||
131 | //printf("spi mode: %d\n", mode); | |||
132 | //printf ("bits per word: %d\r\n", bits); | |||
133 | //printf ("max speed: %lu Hz (%lu kHz)\r\n", | |||
134 | // (unsigned long) speed, ((unsigned long) speed) / 1000); | |||
135 | //#endif /* DEBUG */ | |||
136 | return fd; | |||
137 | } | |||
138 | ||||
139 | int configureSpiFromFd (int fd) | |||
140 | { | |||
141 | setMode (fd, 0); | |||
142 | /* bits per word */ | |||
143 | if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) | |||
144 | pabort ("can't set bits per word"); |